[NEW] Room header layout (#521)
After Width: | Height: | Size: 222 B |
After Width: | Height: | Size: 559 B |
After Width: | Height: | Size: 981 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 408 B |
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 224 B |
After Width: | Height: | Size: 659 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 313 B |
After Width: | Height: | Size: 954 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 390 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 3.2 KiB |
|
@ -15,9 +15,9 @@ const RoomTypeIcon = ({ type, size, style }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'c') {
|
if (type === 'c') {
|
||||||
return <Image source={{ uri: 'subscription_hashtag' }} style={[styles.style, style, { width: size, height: size }]} />;
|
return <Image source={{ uri: 'hashtag' }} style={[styles.style, style, { width: size, height: size }]} />;
|
||||||
}
|
}
|
||||||
return <Image source={{ uri: 'subscription_lock' }} style={[styles.style, style, { width: size, height: size }]} />;
|
return <Image source={{ uri: 'lock' }} style={[styles.style, style, { width: size, height: size }]} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomTypeIcon.propTypes = {
|
RoomTypeIcon.propTypes = {
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
|
||||||
View, StyleSheet, Text, Keyboard, LayoutAnimation
|
|
||||||
} from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import I18n from '../i18n';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
typing: {
|
|
||||||
transform: [{ scaleY: -1 }],
|
|
||||||
fontWeight: 'bold',
|
|
||||||
paddingHorizontal: 15,
|
|
||||||
height: 25
|
|
||||||
},
|
|
||||||
emptySpace: {
|
|
||||||
height: 5
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@connect(state => ({
|
|
||||||
username: state.login.user && state.login.user.username,
|
|
||||||
usersTyping: state.room.usersTyping
|
|
||||||
}))
|
|
||||||
export default class Typing extends React.Component {
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
const { usersTyping } = this.props;
|
|
||||||
return usersTyping.join() !== nextProps.usersTyping.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUpdate() {
|
|
||||||
LayoutAnimation.easeInEaseOut();
|
|
||||||
}
|
|
||||||
|
|
||||||
onPress = () => {
|
|
||||||
Keyboard.dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
get usersTyping() {
|
|
||||||
const { usersTyping, username } = this.props;
|
|
||||||
const users = usersTyping.filter(_username => username !== _username);
|
|
||||||
return users.length ? `${ users.join(', ') } ${ users.length > 1 ? I18n.t('are_typing') : I18n.t('is_typing') }` : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { usersTyping } = this;
|
|
||||||
|
|
||||||
if (!usersTyping) {
|
|
||||||
return <View style={styles.emptySpace} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<Text style={styles.typing} onPress={() => this.onPress()}>{usersTyping}</Text>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Typing.propTypes = {
|
|
||||||
username: PropTypes.string,
|
|
||||||
usersTyping: PropTypes.array
|
|
||||||
};
|
|
|
@ -75,20 +75,13 @@ const handleTogglePinRequest = function* handleTogglePinRequest({ message }) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const goRoom = function* goRoom({ rid, name }) {
|
const goRoom = function* goRoom({ rid }) {
|
||||||
yield Navigation.popToRoot('RoomsListView');
|
yield Navigation.popToRoot('RoomsListView');
|
||||||
Navigation.push('RoomsListView', {
|
Navigation.push('RoomsListView', {
|
||||||
component: {
|
component: {
|
||||||
name: 'RoomView',
|
name: 'RoomView',
|
||||||
passProps: {
|
passProps: {
|
||||||
rid
|
rid
|
||||||
},
|
|
||||||
options: {
|
|
||||||
topBar: {
|
|
||||||
title: {
|
|
||||||
text: name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -99,10 +92,10 @@ const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
|
||||||
const { username } = message.u;
|
const { username } = message.u;
|
||||||
const subscriptions = database.objects('subscriptions').filtered('name = $0', username);
|
const subscriptions = database.objects('subscriptions').filtered('name = $0', username);
|
||||||
if (subscriptions.length) {
|
if (subscriptions.length) {
|
||||||
yield goRoom({ rid: subscriptions[0].rid, name: subscriptions[0].name });
|
yield goRoom({ rid: subscriptions[0].rid });
|
||||||
} else {
|
} else {
|
||||||
const room = yield RocketChat.createDirectMessage(username);
|
const room = yield RocketChat.createDirectMessage(username);
|
||||||
yield goRoom({ rid: room.rid, name: username });
|
yield goRoom({ rid: room.rid });
|
||||||
}
|
}
|
||||||
yield delay(500);
|
yield delay(500);
|
||||||
yield put(replyInit(message, false));
|
yield put(replyInit(message, false));
|
||||||
|
|
|
@ -125,20 +125,13 @@ export default class CreateChannelView extends LoggedView {
|
||||||
const msg = error.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') });
|
const msg = error.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') });
|
||||||
showErrorAlert(msg);
|
showErrorAlert(msg);
|
||||||
} else {
|
} else {
|
||||||
const { rid, name } = result;
|
const { rid } = result;
|
||||||
await Navigation.dismissModal(componentId);
|
await Navigation.dismissModal(componentId);
|
||||||
Navigation.push('RoomsListView', {
|
Navigation.push('RoomsListView', {
|
||||||
component: {
|
component: {
|
||||||
name: 'RoomView',
|
name: 'RoomView',
|
||||||
passProps: {
|
passProps: {
|
||||||
rid
|
rid
|
||||||
},
|
|
||||||
options: {
|
|
||||||
topBar: {
|
|
||||||
title: {
|
|
||||||
text: name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -115,10 +115,10 @@ export default class RoomMembersView extends LoggedView {
|
||||||
try {
|
try {
|
||||||
const subscriptions = database.objects('subscriptions').filtered('name = $0', item.username);
|
const subscriptions = database.objects('subscriptions').filtered('name = $0', item.username);
|
||||||
if (subscriptions.length) {
|
if (subscriptions.length) {
|
||||||
this.goRoom({ rid: subscriptions[0].rid, name: subscriptions[0].name });
|
this.goRoom({ rid: subscriptions[0].rid });
|
||||||
} else {
|
} else {
|
||||||
const room = await RocketChat.createDirectMessage(item.username);
|
const room = await RocketChat.createDirectMessage(item.username);
|
||||||
this.goRoom({ rid: room.rid, name: item.username });
|
this.goRoom({ rid: room.rid });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('onPressUser', e);
|
log('onPressUser', e);
|
||||||
|
@ -152,7 +152,7 @@ export default class RoomMembersView extends LoggedView {
|
||||||
await this.setState({ room });
|
await this.setState({ room });
|
||||||
}
|
}
|
||||||
|
|
||||||
goRoom = async({ rid, name }) => {
|
goRoom = async({ rid }) => {
|
||||||
const { componentId } = this.props;
|
const { componentId } = this.props;
|
||||||
await Navigation.popToRoot(componentId);
|
await Navigation.popToRoot(componentId);
|
||||||
Navigation.push('RoomsListView', {
|
Navigation.push('RoomsListView', {
|
||||||
|
@ -160,13 +160,6 @@ export default class RoomMembersView extends LoggedView {
|
||||||
name: 'RoomView',
|
name: 'RoomView',
|
||||||
passProps: {
|
passProps: {
|
||||||
rid
|
rid
|
||||||
},
|
|
||||||
options: {
|
|
||||||
topBar: {
|
|
||||||
title: {
|
|
||||||
text: name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
View, Text, StyleSheet, Image, Platform, LayoutAnimation
|
||||||
|
} from 'react-native';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { responsive } from 'react-native-responsive-ui';
|
||||||
|
import equal from 'deep-equal';
|
||||||
|
|
||||||
|
import I18n from '../../../i18n';
|
||||||
|
import { STATUS_COLORS } from '../../../constants/colors';
|
||||||
|
|
||||||
|
const isIOS = () => Platform.OS === 'ios';
|
||||||
|
const TITLE_SIZE = 18;
|
||||||
|
const ICON_SIZE = 16;
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: isIOS() ? 'transparent' : '#2F343D',
|
||||||
|
height: 44
|
||||||
|
},
|
||||||
|
titleContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: isIOS() ? '#0C0D0F' : '#fff',
|
||||||
|
fontSize: TITLE_SIZE,
|
||||||
|
fontWeight: '500'
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
width: ICON_SIZE,
|
||||||
|
height: ICON_SIZE,
|
||||||
|
marginRight: 5,
|
||||||
|
tintColor: isIOS() ? '#9EA2A8' : '#fff'
|
||||||
|
},
|
||||||
|
typing: {
|
||||||
|
color: isIOS() ? '#9EA2A8' : '#fff',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
|
typingUsers: {
|
||||||
|
fontWeight: '600'
|
||||||
|
},
|
||||||
|
alignItemsFlexStart: {
|
||||||
|
alignItems: 'flex-start'
|
||||||
|
},
|
||||||
|
alignItemsCenter: {
|
||||||
|
alignItems: 'center'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@responsive
|
||||||
|
@connect((state) => {
|
||||||
|
let status = '';
|
||||||
|
let title = '';
|
||||||
|
if (state.room.t === 'd') {
|
||||||
|
const { id: loggedUserId } = state.login.user;
|
||||||
|
const userId = state.room.rid.replace(loggedUserId, '').trim();
|
||||||
|
if (userId === loggedUserId) {
|
||||||
|
status = state.login.user.status; // eslint-disable-line
|
||||||
|
} else {
|
||||||
|
const user = state.activeUsers[userId];
|
||||||
|
status = (user && user.status) || 'offline';
|
||||||
|
}
|
||||||
|
title = state.settings.UI_Use_Real_Name ? state.room.fname : state.room.name;
|
||||||
|
} else {
|
||||||
|
title = state.room.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { username } = state.login.user;
|
||||||
|
const { usersTyping } = state.room;
|
||||||
|
const otherUsersTyping = usersTyping.filter(_username => _username !== username);
|
||||||
|
|
||||||
|
return {
|
||||||
|
usersTyping: otherUsersTyping,
|
||||||
|
type: state.room.t,
|
||||||
|
title,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
})
|
||||||
|
export default class RoomHeaderView extends PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
type: PropTypes.string,
|
||||||
|
window: PropTypes.object,
|
||||||
|
usersTyping: PropTypes.array,
|
||||||
|
status: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const { usersTyping } = this.props;
|
||||||
|
if (!equal(prevProps.usersTyping, usersTyping)) {
|
||||||
|
LayoutAnimation.easeInEaseOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get typing() {
|
||||||
|
const { usersTyping } = this.props;
|
||||||
|
let usersText;
|
||||||
|
if (!usersTyping.length) {
|
||||||
|
return null;
|
||||||
|
} else if (usersTyping.length === 2) {
|
||||||
|
usersText = usersTyping.join(` ${ I18n.t('and') } `);
|
||||||
|
} else {
|
||||||
|
usersText = usersTyping.join(', ');
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Text style={styles.typing} numberOfLines={1}>
|
||||||
|
<Text style={styles.typingUsers}>{usersText} </Text>
|
||||||
|
{ usersTyping.length > 1 ? I18n.t('are_typing') : I18n.t('is_typing') }
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
window, title, type, status, usersTyping
|
||||||
|
} = this.props;
|
||||||
|
const icon = {
|
||||||
|
d: 'mention',
|
||||||
|
c: 'hashtag'
|
||||||
|
}[type] || 'lock';
|
||||||
|
const portrait = window.height > window.width;
|
||||||
|
let height = 44;
|
||||||
|
let scale = 1;
|
||||||
|
|
||||||
|
if (!portrait) {
|
||||||
|
if (isIOS()) {
|
||||||
|
height = 32;
|
||||||
|
}
|
||||||
|
if (usersTyping.length > 0) {
|
||||||
|
scale = 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.container,
|
||||||
|
portrait ? styles.alignItemsFlexStart : styles.alignItemsCenter,
|
||||||
|
{ maxWidth: window.width - 150, height }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View style={styles.titleContainer}>
|
||||||
|
<Image
|
||||||
|
source={{ uri: icon }}
|
||||||
|
style={[
|
||||||
|
styles.type,
|
||||||
|
{
|
||||||
|
width: ICON_SIZE * scale,
|
||||||
|
height: ICON_SIZE * scale
|
||||||
|
},
|
||||||
|
type === 'd' && { tintColor: STATUS_COLORS[status] }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Text style={[styles.title, { fontSize: TITLE_SIZE * scale }]} numberOfLines={1}>{title}</Text>
|
||||||
|
</View>
|
||||||
|
{this.typing}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Separator from './Separator';
|
import Separator from './Separator';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import Typing from '../../containers/Typing';
|
|
||||||
import database from '../../lib/realm';
|
import database from '../../lib/realm';
|
||||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||||
import throttle from '../../utils/throttle';
|
import throttle from '../../utils/throttle';
|
||||||
|
@ -79,7 +78,6 @@ export class List extends React.Component {
|
||||||
keyExtractor={item => item._id}
|
keyExtractor={item => item._id}
|
||||||
onEndReachedThreshold={100}
|
onEndReachedThreshold={100}
|
||||||
renderFooter={renderFooter}
|
renderFooter={renderFooter}
|
||||||
renderHeader={() => <Typing />}
|
|
||||||
onEndReached={() => onEndReached(this.data[this.data.length - 1])}
|
onEndReached={() => onEndReached(this.data[this.data.length - 1])}
|
||||||
dataSource={this.dataSource}
|
dataSource={this.dataSource}
|
||||||
renderRow={(item, previousItem) => renderRow(item, previousItem)}
|
renderRow={(item, previousItem) => renderRow(item, previousItem)}
|
||||||
|
|
|
@ -51,6 +51,13 @@ export default class RoomView extends LoggedView {
|
||||||
static options() {
|
static options() {
|
||||||
return {
|
return {
|
||||||
topBar: {
|
topBar: {
|
||||||
|
animate: true,
|
||||||
|
title: {
|
||||||
|
component: {
|
||||||
|
name: 'RoomHeaderView',
|
||||||
|
alignment: 'fill'
|
||||||
|
}
|
||||||
|
},
|
||||||
rightButtons: [{
|
rightButtons: [{
|
||||||
id: 'more',
|
id: 'more',
|
||||||
testID: 'room-view-header-actions',
|
testID: 'room-view-header-actions',
|
||||||
|
@ -224,22 +231,14 @@ export default class RoomView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRoom = () => {
|
updateRoom = () => {
|
||||||
const { componentId, openRoom, setLastOpen } = this.props;
|
const { openRoom, setLastOpen } = this.props;
|
||||||
|
|
||||||
if (this.rooms.length > 0) {
|
if (this.rooms.length > 0) {
|
||||||
const { room: prevRoom } = this.state;
|
const { room: prevRoom } = this.state;
|
||||||
const room = JSON.parse(JSON.stringify(this.rooms[0] || {}));
|
const room = JSON.parse(JSON.stringify(this.rooms[0] || {}));
|
||||||
LayoutAnimation.easeInEaseOut();
|
|
||||||
this.internalSetState({ room });
|
this.internalSetState({ room });
|
||||||
|
|
||||||
if (!prevRoom.rid) {
|
if (!prevRoom.rid) {
|
||||||
Navigation.mergeOptions(componentId, {
|
|
||||||
topBar: {
|
|
||||||
title: {
|
|
||||||
text: room.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
openRoom({
|
openRoom({
|
||||||
...room
|
...room
|
||||||
});
|
});
|
||||||
|
|
|
@ -378,19 +378,12 @@ export default class RoomsListView extends LoggedView {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
goRoom = (rid, name) => {
|
goRoom = (rid) => {
|
||||||
Navigation.push('RoomsListView', {
|
Navigation.push('RoomsListView', {
|
||||||
component: {
|
component: {
|
||||||
name: 'RoomView',
|
name: 'RoomView',
|
||||||
passProps: {
|
passProps: {
|
||||||
rid
|
rid
|
||||||
},
|
|
||||||
options: {
|
|
||||||
topBar: {
|
|
||||||
title: {
|
|
||||||
text: name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -399,8 +392,8 @@ export default class RoomsListView extends LoggedView {
|
||||||
|
|
||||||
_onPressItem = async(item = {}) => {
|
_onPressItem = async(item = {}) => {
|
||||||
if (!item.search) {
|
if (!item.search) {
|
||||||
const { rid, name } = item;
|
const { rid } = item;
|
||||||
return this.goRoom(rid, name);
|
return this.goRoom(rid);
|
||||||
}
|
}
|
||||||
if (item.t === 'd') {
|
if (item.t === 'd') {
|
||||||
// if user is using the search we need first to join/create room
|
// if user is using the search we need first to join/create room
|
||||||
|
@ -408,13 +401,13 @@ export default class RoomsListView extends LoggedView {
|
||||||
const { username } = item;
|
const { username } = item;
|
||||||
const sub = await RocketChat.createDirectMessage(username);
|
const sub = await RocketChat.createDirectMessage(username);
|
||||||
const { rid } = sub;
|
const { rid } = sub;
|
||||||
return this.goRoom(rid, username);
|
return this.goRoom(rid);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('RoomsListView._onPressItem', e);
|
log('RoomsListView._onPressItem', e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { rid, name } = item;
|
const { rid } = item;
|
||||||
return this.goRoom(rid, name);
|
return this.goRoom(rid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ProfileView from './ProfileView';
|
||||||
import RoomsListHeaderView from './RoomsListView/Header';
|
import RoomsListHeaderView from './RoomsListView/Header';
|
||||||
import RoomsListView from './RoomsListView';
|
import RoomsListView from './RoomsListView';
|
||||||
import RoomView from './RoomView';
|
import RoomView from './RoomView';
|
||||||
|
import RoomHeaderView from './RoomView/Header';
|
||||||
import SettingsView from './SettingsView';
|
import SettingsView from './SettingsView';
|
||||||
import Sidebar from '../containers/Sidebar';
|
import Sidebar from '../containers/Sidebar';
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ export const registerScreens = (store) => {
|
||||||
Navigation.registerComponentWithRedux('RoomsListHeaderView', () => RoomsListHeaderView, Provider, store);
|
Navigation.registerComponentWithRedux('RoomsListHeaderView', () => RoomsListHeaderView, Provider, store);
|
||||||
Navigation.registerComponentWithRedux('RoomsListView', () => gestureHandlerRootHOC(RoomsListView), Provider, store);
|
Navigation.registerComponentWithRedux('RoomsListView', () => gestureHandlerRootHOC(RoomsListView), Provider, store);
|
||||||
Navigation.registerComponentWithRedux('RoomView', () => gestureHandlerRootHOC(RoomView), Provider, store);
|
Navigation.registerComponentWithRedux('RoomView', () => gestureHandlerRootHOC(RoomView), Provider, store);
|
||||||
|
Navigation.registerComponentWithRedux('RoomHeaderView', () => RoomHeaderView, Provider, store);
|
||||||
Navigation.registerComponentWithRedux('SettingsView', () => SettingsView, Provider, store);
|
Navigation.registerComponentWithRedux('SettingsView', () => SettingsView, Provider, store);
|
||||||
Navigation.registerComponentWithRedux('Sidebar', () => Sidebar, Provider, store);
|
Navigation.registerComponentWithRedux('Sidebar', () => Sidebar, Provider, store);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "Cell Subscription Lock.png",
|
"filename" : "hashtag.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "Cell Subscription Lock@2x.png",
|
"filename" : "hashtag@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "Cell Subscription Lock@3x.png",
|
"filename" : "hashtag@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 224 B |
After Width: | Height: | Size: 313 B |
|
@ -2,17 +2,17 @@
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "Cell Subscription Hashtag.png",
|
"filename" : "lock.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "Cell Subscription Hashtag@2x.png",
|
"filename" : "lock@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "Cell Subscription Hashtag@3x.png",
|
"filename" : "lock@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
After Width: | Height: | Size: 408 B |
After Width: | Height: | Size: 659 B |
After Width: | Height: | Size: 954 B |
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "mention.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "mention@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "mention@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 115 B |
Before Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 195 B |
Before Width: | Height: | Size: 348 B |
Before Width: | Height: | Size: 481 B |