Enable iOS Share Extension with TableView (#1418)
* Enable iOS Share Extension with TableView * show channel display_name when main app channel is dm or gm * feedback review
This commit is contained in:
parent
94af2d5725
commit
9a0a43ae35
8 changed files with 168 additions and 69 deletions
35
NOTICE.txt
35
NOTICE.txt
|
|
@ -2623,3 +2623,38 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
## react-native-tableview
|
||||
|
||||
Native iOS UITableView for React Native with JSON support.
|
||||
|
||||
* HOMEPAGE:
|
||||
* https://github.com/aksonov/react-native-tableview
|
||||
|
||||
* LICENSE:
|
||||
|
||||
Copyright (c) 2015, aksonov
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
7FC200E81EBB65370099331B /* libReactNativeNavigation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC200DF1EBB65100099331B /* libReactNativeNavigation.a */; };
|
||||
7FC649EE1FE983660074E4C7 /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 349FBA7338E74D9BBD709528 /* EvilIcons.ttf */; };
|
||||
7FC649F01FE9B5D90074E4C7 /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D4B1B363C2414DA19C1AC521 /* OpenSans-Bold.ttf */; };
|
||||
7FD8DEDE2029EDB7001AAC5E /* libRNTableView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FD8DEDA2029ECDF001AAC5E /* libRNTableView.a */; };
|
||||
7FDB92B11F706F58006CDFD1 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDB92A71F706F45006CDFD1 /* libRNImagePicker.a */; };
|
||||
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB10971F6101710039A015 /* BlurAppScreen.m */; };
|
||||
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB109A1F61019C0039A015 /* MattermostManaged.m */; };
|
||||
|
|
@ -531,6 +532,13 @@
|
|||
remoteGlobalIDString = D8AFADBD1BEE6F3F00A4592D;
|
||||
remoteInfo = ReactNativeNavigation;
|
||||
};
|
||||
7FD8DED92029ECDF001AAC5E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 7FD8DE972029ECDE001AAC5E /* RNTableView.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 873769951B7CD6E900F7C3C2;
|
||||
remoteInfo = RNTableView;
|
||||
};
|
||||
7FDB92A61F706F45006CDFD1 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 7FDB92751F706F45006CDFD1 /* RNImagePicker.xcodeproj */;
|
||||
|
|
@ -678,6 +686,7 @@
|
|||
7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PerformRequests.m; sourceTree = "<group>"; };
|
||||
7F7D7F52201645D300D31155 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ios/ReactNativePermissions.xcodeproj"; sourceTree = "<group>"; };
|
||||
7FC200BC1EBB65100099331B /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = "../node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj"; sourceTree = "<group>"; };
|
||||
7FD8DE972029ECDE001AAC5E /* RNTableView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNTableView.xcodeproj; path = "../node_modules/react-native-tableview/RNTableView.xcodeproj"; sourceTree = "<group>"; };
|
||||
7FDB92751F706F45006CDFD1 /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNImagePicker.xcodeproj; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = "<group>"; };
|
||||
7FEB10961F6101710039A015 /* BlurAppScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlurAppScreen.h; path = Mattermost/BlurAppScreen.h; sourceTree = "<group>"; };
|
||||
7FEB10971F6101710039A015 /* BlurAppScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BlurAppScreen.m; path = Mattermost/BlurAppScreen.m; sourceTree = "<group>"; };
|
||||
|
|
@ -806,6 +815,7 @@
|
|||
7FFE32EA1FD9CD050038C7A0 /* libReact.a in Frameworks */,
|
||||
7FFE32E91FD9CCF40038C7A0 /* libRCTAnimation.a in Frameworks */,
|
||||
7FFE32E81FD9CCDE0038C7A0 /* libRCTCameraRoll.a in Frameworks */,
|
||||
7FD8DEDE2029EDB7001AAC5E /* libRNTableView.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -1201,6 +1211,14 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7FD8DE982029ECDE001AAC5E /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7FD8DEDA2029ECDF001AAC5E /* libRNTableView.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7FDB92761F706F45006CDFD1 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -1259,6 +1277,7 @@
|
|||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7FD8DE972029ECDE001AAC5E /* RNTableView.xcodeproj */,
|
||||
7F7D7F52201645D300D31155 /* ReactNativePermissions.xcodeproj */,
|
||||
7FDB92751F706F45006CDFD1 /* RNImagePicker.xcodeproj */,
|
||||
37ABD3971F4CE13B001FDE6B /* ART.xcodeproj */,
|
||||
|
|
@ -1592,6 +1611,10 @@
|
|||
ProductGroup = 7FDF28C41E1F4B1F00DBBE56 /* Products */;
|
||||
ProjectRef = 2CBE9C0FB56E4FDA96C30792 /* RNSVG.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 7FD8DE982029ECDE001AAC5E /* Products */;
|
||||
ProjectRef = 7FD8DE972029ECDE001AAC5E /* RNTableView.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 7FDF28EE1E1F4B4E00DBBE56 /* Products */;
|
||||
ProjectRef = 2B25899FDAC149EB96ED3305 /* RNVectorIcons.xcodeproj */;
|
||||
|
|
@ -2024,6 +2047,13 @@
|
|||
remoteRef = 7FC200DE1EBB65100099331B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
7FD8DEDA2029ECDF001AAC5E /* libRNTableView.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRNTableView.a;
|
||||
remoteRef = 7FD8DED92029ECDF001AAC5E /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
7FDB92A71F706F45006CDFD1 /* libRNImagePicker.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
|
|
@ -2530,6 +2560,7 @@
|
|||
"$(SRCROOT)/../node_modules/react-native-video/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-doc-viewer/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safe-area/ios/RNSafeArea",
|
||||
"$(SRCROOT)/../node_modules/react-native-tableview/**",
|
||||
);
|
||||
INFOPLIST_FILE = MattermostShare/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
|
|
@ -2589,6 +2620,7 @@
|
|||
"$(SRCROOT)/../node_modules/react-native-video/ios",
|
||||
"$(SRCROOT)/../node_modules/react-native-doc-viewer/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safe-area/ios/RNSafeArea",
|
||||
"$(SRCROOT)/../node_modules/react-native-tableview/**",
|
||||
);
|
||||
INFOPLIST_FILE = MattermostShare/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
"react-native-slider": "0.11.0",
|
||||
"react-native-status-bar-size": "0.3.3",
|
||||
"react-native-svg": "6.1.3",
|
||||
"react-native-tableview": "2.1.0",
|
||||
"react-native-tooltip": "enahum/react-native-tooltip",
|
||||
"react-native-vector-icons": "4.5.0",
|
||||
"react-native-video": "2.0.0",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {Preferences} from 'mattermost-redux/constants';
|
|||
import SearchBar from 'app/components/search_bar';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import ExtensionChannelItem from 'share_extension/common/extension_channel_item';
|
||||
import ExtensionChannelItem from './extension_channel_item';
|
||||
|
||||
const defaultTheme = Preferences.THEMES.default;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ import React, {PureComponent} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
SectionList,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {intlShape} from 'react-intl';
|
||||
import TableView from 'react-native-tableview';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome';
|
||||
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
import {getChannelsInTeam, getDirectChannels} from 'mattermost-redux/selectors/entities/channels';
|
||||
|
|
@ -18,8 +19,6 @@ import {getChannelsInTeam, getDirectChannels} from 'mattermost-redux/selectors/e
|
|||
import SearchBar from 'app/components/search_bar';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import ExtensionChannelItem from 'share_extension/common/extension_channel_item';
|
||||
|
||||
import ExtensionNavBar from './extension_nav_bar';
|
||||
|
||||
export default class ExtensionChannels extends PureComponent {
|
||||
|
|
@ -112,6 +111,18 @@ export default class ExtensionChannels extends PureComponent {
|
|||
const direct = getDirectChannels({entities});
|
||||
const channels = channelIds.map((id) => this.props.entities.channels.channels[id]).concat(direct);
|
||||
|
||||
const icons = await Promise.all([
|
||||
Icon.getImageSource('globe', 16, this.props.theme.centerChannelColor),
|
||||
Icon.getImageSource('lock', 16, this.props.theme.centerChannelColor),
|
||||
Icon.getImageSource('user', 16, this.props.theme.centerChannelColor),
|
||||
Icon.getImageSource('users', 16, this.props.theme.centerChannelColor)
|
||||
]);
|
||||
|
||||
this.publicChannelIcon = icons[0];
|
||||
this.privateChannelIcon = icons[1];
|
||||
this.dmChannelIcon = icons[2];
|
||||
this.gmChannelIcon = icons[3];
|
||||
|
||||
this.setState({
|
||||
channels
|
||||
}, () => {
|
||||
|
|
@ -134,12 +145,20 @@ export default class ExtensionChannels extends PureComponent {
|
|||
});
|
||||
};
|
||||
|
||||
handleSelectChannel = (channel) => {
|
||||
this.props.onSelectChannel(channel);
|
||||
this.goBack();
|
||||
handleSelectChannel = (selected) => {
|
||||
const {sections} = this.state;
|
||||
const section = sections.find((s) => s.id === selected.detail);
|
||||
if (section) {
|
||||
const channel = section.data.find((c) => c.id === selected.value);
|
||||
if (channel) {
|
||||
this.props.onSelectChannel(channel);
|
||||
this.goBack();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
renderBody = (styles) => {
|
||||
const {theme} = this.props;
|
||||
const {error, sections} = this.state;
|
||||
|
||||
if (error) {
|
||||
|
|
@ -161,45 +180,22 @@ export default class ExtensionChannels extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<SectionList
|
||||
sections={sections}
|
||||
ListHeaderComponent={this.renderSearchBar(styles)}
|
||||
ItemSeparatorComponent={this.renderItemSeparator}
|
||||
renderItem={this.renderItem}
|
||||
renderSectionHeader={this.renderSectionHeader}
|
||||
keyExtractor={this.keyExtractor}
|
||||
keyboardShouldPersistTaps='always'
|
||||
keyboardDismissMode='on-drag'
|
||||
initialNumToRender={10}
|
||||
maxToRenderPerBatch={10}
|
||||
stickySectionHeadersEnabled={true}
|
||||
scrollEventThrottle={100}
|
||||
windowSize={5}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderItem = ({item}) => {
|
||||
const {currentChannelId, theme} = this.props;
|
||||
|
||||
return (
|
||||
<ExtensionChannelItem
|
||||
channel={item}
|
||||
currentChannelId={currentChannelId}
|
||||
onSelectChannel={this.handleSelectChannel}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderItemSeparator = () => {
|
||||
const {theme} = this.props;
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
<View style={styles.separatorContainer}>
|
||||
<View style={styles.separator}/>
|
||||
</View>
|
||||
<TableView
|
||||
tableViewStyle={TableView.Consts.Style.Plain}
|
||||
tableViewCellStyle={TableView.Consts.CellStyle.Default}
|
||||
separatorColor={changeOpacity(theme.centerChannelColor, 0.5)}
|
||||
tintColor={theme.linkColor}
|
||||
detailFontSize={16}
|
||||
detailTextColor={theme.centerChannelColor}
|
||||
headerFontSize={15}
|
||||
headerTextColor={changeOpacity(theme.centerChannelColor, 0.6)}
|
||||
style={styles.flex}
|
||||
>
|
||||
<TableView.Section>
|
||||
<TableView.Cell>{this.renderSearchBar(styles)}</TableView.Cell>
|
||||
</TableView.Section>
|
||||
{this.renderSections()}
|
||||
</TableView>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -227,29 +223,53 @@ export default class ExtensionChannels extends PureComponent {
|
|||
);
|
||||
};
|
||||
|
||||
renderSectionHeader = ({section}) => {
|
||||
const {intl} = this.context;
|
||||
const {theme} = this.props;
|
||||
const styles = getStyleSheet(theme);
|
||||
const {
|
||||
defaultMessage,
|
||||
id
|
||||
} = section;
|
||||
renderSections = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {currentChannelId} = this.props;
|
||||
const {sections} = this.state;
|
||||
|
||||
return (
|
||||
<View style={[styles.titleContainer, {backgroundColor: theme.centerChannelBg}]}>
|
||||
<View style={{backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), justifyContent: 'center'}}>
|
||||
<Text style={styles.title}>
|
||||
{intl.formatMessage({id, defaultMessage}).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
return sections.map((s) => {
|
||||
const items = s.data.map((c) => {
|
||||
let icon;
|
||||
switch (c.type) {
|
||||
case General.OPEN_CHANNEL:
|
||||
icon = this.publicChannelIcon.uri;
|
||||
break;
|
||||
case General.PRIVATE_CHANNEL:
|
||||
icon = this.privateChannelIcon.uri;
|
||||
break;
|
||||
case General.DM_CHANNEL:
|
||||
icon = this.dmChannelIcon.uri;
|
||||
break;
|
||||
case General.GM_CHANNEL:
|
||||
icon = this.gmChannelIcon.uri;
|
||||
break;
|
||||
}
|
||||
|
||||
sort = (a, b) => {
|
||||
const locale = DeviceInfo.getDeviceLocale().split('-')[0];
|
||||
return a.localeCompare(b, locale, {numeric: true});
|
||||
return (
|
||||
<TableView.Item
|
||||
key={c.id}
|
||||
value={c.id}
|
||||
detail={s.id}
|
||||
selected={c.id === currentChannelId}
|
||||
onPress={this.handleSelectChannel}
|
||||
image={icon}
|
||||
>
|
||||
{c.display_name}
|
||||
</TableView.Item>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<TableView.Section
|
||||
key={s.id}
|
||||
label={formatMessage({id: s.id, defaultMessage: s.defaultMessage})}
|
||||
headerHeight={30}
|
||||
>
|
||||
{items}
|
||||
</TableView.Section>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
sortDisplayName = (a, b) => {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import LocalAuth from 'react-native-local-auth';
|
|||
import RNFetchBlob from 'react-native-fetch-blob';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getFormattedFileSize, lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||
|
||||
import mattermostBucket from 'app/mattermost_bucket';
|
||||
|
|
@ -40,7 +42,6 @@ import {
|
|||
import ExtensionChannels from './extension_channels';
|
||||
import ExtensionNavBar from './extension_nav_bar';
|
||||
import ExtensionTeams from './extension_teams';
|
||||
import {General} from 'mattermost-redux/constants/index';
|
||||
|
||||
const ShareExtension = NativeModules.MattermostShare;
|
||||
const MAX_INPUT_HEIGHT = 95;
|
||||
|
|
@ -189,13 +190,17 @@ export default class ExtensionPost extends PureComponent {
|
|||
const {credentials} = entities.general;
|
||||
const {currentUserId} = entities.users;
|
||||
const team = entities.teams.teams[entities.teams.currentTeamId];
|
||||
const channel = entities.channels.channels[entities.channels.currentChannelId];
|
||||
let channel = entities.channels.channels[entities.channels.currentChannelId];
|
||||
const items = await ShareExtension.data(Config.AppGroupId);
|
||||
const text = [];
|
||||
const urls = [];
|
||||
const files = [];
|
||||
let totalSize = 0;
|
||||
|
||||
if (channel.type === General.GM_CHANNEL || channel.type === General.DM_CHANNEL) {
|
||||
channel = getChannel({entities}, channel.id);
|
||||
}
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
switch (item.type) {
|
||||
|
|
|
|||
|
|
@ -5311,6 +5311,12 @@ react-native-tab-view@^0.0.74:
|
|||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-native-tableview@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-tableview/-/react-native-tableview-2.1.0.tgz#d98b8303728b5ff4860612f05163028735bb3b07"
|
||||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-native-tooltip@enahum/react-native-tooltip:
|
||||
version "5.1.1"
|
||||
resolved "https://codeload.github.com/enahum/react-native-tooltip/tar.gz/eb47f93a728813b58c01f23ec84f0b8b1bd70bd0"
|
||||
|
|
|
|||
Loading…
Reference in a new issue