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