diff --git a/CHANGELOG.md b/CHANGELOG.md index 01ecf5881..8d23c5e7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ # Mattermost Mobile Apps Changelog -## v1.1 Release (In Progress) +## v1.1 Release -- Planned Release Date: August 2017 +- Release Date: August 2017 +- Server Versions Supported: Server v3.10+ is required, Self-Signed SSL Certificates are not yet supported ### Highlights @@ -13,6 +14,13 @@ #### Emoji Reactions - View Emoji Reactions on a post +#### Group Messages +- Start Direct and Group Messages from the same screen + +#### Improved Performance on Poor Connections +- Added auto-retry to automatically reattempt to get posts if the network connection is intermittent +- Added manual loading option if auto-retry fails to retrieve new posts + ### Improvements - Android: Added Big Text support for Android notifications, so they expand to show more details - Added a Reset Cache option @@ -20,17 +28,21 @@ - Tapping on an @username mention opens the user's profile - Disabled the send button while attachments upload - Adjusted margins on icons and elsewhere to make spacing more consistent -- iOS: mattermost:// links now open the new app +- iOS URL scheme: mattermost:// links now open the new app +- About Mattermost page now includes a link to NOTICES.txt for platform and the mobile app +- Various UI improvements ### Bug Fixes - Fixed an issue where sometimes an unmounted badge caused app to crash on start up - Group Direct Messages now show the correct member count - Hamburger icon does not break after swiping to close sidebar -- Fixed an issue with some image thumbnails showing up blurry +- Fixed an issue with some image thumbnails appearing out of focus - Uploading a file and then leaving the channel no longer shows the file in a perpetual loading state -- For private channels, the last member can no longer delete the channel if the EE server pemissions do not allow it -- When SSO login fails, error messages are now shown +- For private channels, the last member can no longer delete the channel if the EE server permissions do not allow it +- Error messages are now shown when SSO login fails - Android: Leaving a channel now redirects to Town Square instead of the Town Square info page +- Fixed create new public channel screen shown twice when trying to create a channel +- Tapping on a post will no longer close the keyboard ## v1.0.1 Release diff --git a/android/app/build.gradle b/android/app/build.gradle index 9cb17dda3..d431c0e4f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,7 +91,7 @@ android { applicationId "com.mattermost.rnbeta" minSdkVersion 16 targetSdkVersion 23 - versionCode 44 + versionCode 47 versionName "1.1.0" multiDexEnabled true ndk { diff --git a/app/components/channel_drawer/channels_list/list/list.js b/app/components/channel_drawer/channels_list/list/list.js index d93140896..83bb1216b 100644 --- a/app/components/channel_drawer/channels_list/list/list.js +++ b/app/components/channel_drawer/channels_list/list/list.js @@ -273,7 +273,6 @@ class List extends Component { screenBackgroundColor: theme.centerChannelBg }, passProps: { - channelType: General.PRIVATE_CHANNEL, closeButton: this.closeButton } }); diff --git a/app/components/custom_section_list.js b/app/components/custom_section_list.js index d28f9f565..7d20170e6 100644 --- a/app/components/custom_section_list.js +++ b/app/components/custom_section_list.js @@ -248,6 +248,7 @@ export default class CustomSectionList extends React.PureComponent { sections={this.state.sections} keyExtractor={this.props.keyExtractor} renderItem={this.renderItem} + keyboardShouldPersistTaps='handled' /> ); } diff --git a/app/components/file_attachment_list/file_attachment_list.js b/app/components/file_attachment_list/file_attachment_list.js index f00f772ee..15e54f19f 100644 --- a/app/components/file_attachment_list/file_attachment_list.js +++ b/app/components/file_attachment_list/file_attachment_list.js @@ -4,6 +4,7 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import { + Keyboard, View, TouchableOpacity } from 'react-native'; @@ -69,6 +70,7 @@ export default class FileAttachmentList extends Component { handlePreviewPress = (file) => { this.props.hideOptionsContext(); + Keyboard.dismiss(); preventDoubleTap(this.goToImagePreview, this, this.props.postId, file.id); }; diff --git a/app/components/post_list/post_list.js b/app/components/post_list/post_list.js index 3972e49fe..2ac13bf48 100644 --- a/app/components/post_list/post_list.js +++ b/app/components/post_list/post_list.js @@ -176,6 +176,7 @@ export default class PostList extends PureComponent { {...refreshControl} renderItem={this.renderItem} theme={theme} + keyboardShouldPersistTaps='handled' /> ); } diff --git a/app/screens/create_channel/create_channel.js b/app/screens/create_channel/create_channel.js index c7e7c8d22..d196ff113 100644 --- a/app/screens/create_channel/create_channel.js +++ b/app/screens/create_channel/create_channel.js @@ -128,6 +128,7 @@ class CreateChannel extends PureComponent { }; close = (goBack = false) => { + EventEmitter.emit('closing-create-channel', false); if (goBack) { this.props.navigator.pop({animated: true}); } else { diff --git a/app/screens/more_channels/index.js b/app/screens/more_channels/index.js index 74bfc07f7..92452bd81 100644 --- a/app/screens/more_channels/index.js +++ b/app/screens/more_channels/index.js @@ -3,6 +3,7 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; +import {createSelector} from 'reselect'; import {General} from 'mattermost-redux/constants'; import {getChannels, joinChannel, searchChannels} from 'mattermost-redux/actions/channels'; @@ -16,16 +17,23 @@ import {getTheme} from 'app/selectors/preferences'; import MoreChannels from './more_channels'; +const joinableChannels = createSelector( + getChannelsInCurrentTeam, + getMyChannelMemberships, + (channels, myMembers) => { + return channels.filter((c) => { + return (!myMembers[c.id] && c.type === General.OPEN_CHANNEL); + }); + } +); + function mapStateToProps(state, ownProps) { const {currentUserId} = state.entities.users; const {currentTeamId} = state.entities.teams; const {getChannels: requestStatus} = state.requests.channels; const {config, license} = state.entities.general; const roles = getCurrentUserRoles(state); - const myMembers = getMyChannelMemberships(state); - const channels = getChannelsInCurrentTeam(state).filter((c) => { - return (!myMembers[c.id] && c.type === General.OPEN_CHANNEL); - }); + const channels = joinableChannels(state); return { ...ownProps, diff --git a/app/screens/more_channels/more_channels.js b/app/screens/more_channels/more_channels.js index 03b6e5900..7ffd560f9 100644 --- a/app/screens/more_channels/more_channels.js +++ b/app/screens/more_channels/more_channels.js @@ -58,6 +58,7 @@ class MoreChannels extends PureComponent { this.state = { channels: props.channels.splice(0, General.CHANNELS_CHUNK_SIZE), + createScreenVisible: false, page: 0, adding: false, next: true, @@ -80,6 +81,10 @@ class MoreChannels extends PureComponent { props.navigator.setButtons(buttons); } + componentWillMount() { + EventEmitter.on('closing-create-channel', this.handleCreateScreenVisible); + } + componentDidMount() { // set the timeout to 400 cause is the time that the modal takes to open // Somehow interactionManager doesn't care @@ -101,7 +106,13 @@ class MoreChannels extends PureComponent { this.setState({channels, showNoResults: true}); } - this.headerButtons(nextProps.canCreateChannels, true); + if (!this.state.createScreenVisible) { + this.headerButtons(nextProps.canCreateChannels, true); + } + } + + componentWillUnmount() { + EventEmitter.off('closing-create-channel', this.handleCreateScreenVisible); } close = () => { @@ -112,6 +123,10 @@ class MoreChannels extends PureComponent { this.headerButtons(this.props.canCreateChannels, enabled); }; + handleCreateScreenVisible = (createScreenVisible) => { + this.setState({createScreenVisible}); + }; + headerButtons = (canCreateChannels, enabled) => { const buttons = { leftButtons: [this.leftButton] @@ -182,7 +197,9 @@ class MoreChannels extends PureComponent { this.close(); break; case 'create-pub-channel': - this.onCreateChannel(); + this.setState({ + createScreenVisible: true + }, this.onCreateChannel); break; } } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a39dd1641..8ca9ac881 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -3,11 +3,16 @@ skip_docs platform :ios do before_all do |lane| - if lane == :beta - ensure_git_branch( - branch: 'master' - ) - sh "git checkout -b ios-#{lane}" + if lane == :beta or lane === :release + current_branch = (sh 'git rev-parse --abbrev-ref HEAD').chop! + + UI.user_error!("To cut a beta or a release you need to be on master or in a release branch. + Current branch is #{current_branch} + Exiting") unless current_branch == 'master' or current_branch.start_with?('release') + + if lane == :beta + sh "git checkout -b ios-#{lane}" + end end end @@ -83,10 +88,6 @@ platform :ios do desc 'Deploy a new version to the App Store' lane :release do - ensure_git_branch( - branch: 'master' - ) - match(type: 'appstore', app_identifier: 'com.mattermost.rn') # snapshot @@ -211,11 +212,16 @@ end platform :android do before_all do |lane| - if lane == :alpha - ensure_git_branch( - branch: 'master' - ) - sh "git checkout -b android-#{lane}" + if lane == :alpha or lane === :release + current_branch = (sh 'git rev-parse --abbrev-ref HEAD').chop! + + UI.user_error!("To cut a beta or a release you need to be on master or in a release branch. + Current branch is #{current_branch} + Exiting") unless current_branch == 'master' or current_branch.start_with?('release') + + if lane == :alpha + sh "git checkout -b android-#{lane}" + end end end @@ -281,9 +287,6 @@ platform :android do desc 'Deploy a new version to Google Play' lane :release do - ensure_git_branch( - branch: 'master' - ) android_change_package_identifier(newIdentifier: 'com.mattermost.rn', manifest: './android/app/src/main/AndroidManifest.xml') android_change_string_app_name(newName: 'Mattermost', stringsFile: './android/app/src/main/res/values/strings.xml') android_update_application_id(app_folder_name: 'android/app', application_id: 'com.mattermost.rn') @@ -322,6 +325,12 @@ platform :android do new_string: 'package com.mattermost.rn;' ) + find_replace_string( + path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationDismissReceiver.java', + old_string: 'package com.mattermost.rnbeta;', + new_string: 'package com.mattermost.rn;' + ) + find_replace_string( path_to_file: './android/app/BUCK', old_string: 'package com.mattermost.rnbeta;', diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index d4e56a2bb..f12a9c0d6 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -1320,7 +1320,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 47; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = UQ8HT4Q2XM; HEADER_SEARCH_PATHS = ( @@ -1353,7 +1353,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 47; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = UQ8HT4Q2XM; HEADER_SEARCH_PATHS = ( diff --git a/ios/Mattermost/Info.plist b/ios/Mattermost/Info.plist index 3150eec58..e9078561c 100644 --- a/ios/Mattermost/Info.plist +++ b/ios/Mattermost/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 44 + 47 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/ios/MattermostTests/Info.plist b/ios/MattermostTests/Info.plist index 508bc00a1..e65aa983f 100644 --- a/ios/MattermostTests/Info.plist +++ b/ios/MattermostTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 44 + 47