Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile 1481 messages: Add discussion swiping with delete option #729

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
93 changes: 92 additions & 1 deletion www/addons/messages/controllers/discussions.js
Expand Up @@ -22,13 +22,20 @@ angular.module('mm.addons.messages')
* @name mmaMessagesDiscussionsCtrl
*/
.controller('mmaMessagesDiscussionsCtrl', function($scope, $mmUtil, $mmaMessages, $rootScope, $mmEvents, $mmSite,
mmCoreSplitViewLoad, mmaMessagesNewMessageEvent) {
$translate, $ionicScrollDelegate, $ionicSideMenuDelegate, mmCoreSplitViewLoad, mmaMessagesNewMessageEvent) {
var newMessagesObserver,
siteId = $mmSite.getId(),
discussions;

$scope.canDelete = $mmaMessages.canDeleteDiscussion();
$scope.loaded = false;

var discussionOptionsWidth;
var swiping = false;
var pulling = false;
var swipeStartOffset;
var swipeOffset = 0;

function fetchDiscussions() {
return $mmaMessages.getDiscussions().then(function(discs) {
discussions = discs;
Expand Down Expand Up @@ -92,5 +99,89 @@ angular.module('mm.addons.messages')
newMessagesObserver.off();
}
});

$scope.onDragStart = function(event) {
var element = angular.element(event.currentTarget);
var optionsElement = event.currentTarget.parentElement.getElementsByClassName('mma-messages-discussions-options')[0];
discussionOptionsWidth = optionsElement.clientWidth;

var rightStr = element.css('right');
if (rightStr) {
var rightStrPx = rightStr.substr(0, rightStr.length - 'px'.length); // Remove 'px' from value (e.g. 10px => 10)
swipeStartOffset = parseInt(rightStrPx, 10);
} else {
swipeStartOffset = 0;
}
};

$scope.onDrag = function(event) {
var horizontalMovement = event.gesture.center.pageX - event.gesture.startEvent.center.pageX;

if (!pulling && !swiping) {
var verticalMovement = event.gesture.center.pageY - event.gesture.startEvent.center.pageY;

if (Math.abs(horizontalMovement) > Math.abs(verticalMovement)) {
swiping = true;
$ionicScrollDelegate.freezeScroll(true);
} else if (Math.abs(verticalMovement) > 0) {
pulling = true;
}
}

if (swiping) {
swipeOffset = swipeStartOffset - horizontalMovement;

if (swipeOffset > 0) {
$ionicSideMenuDelegate.canDragContent(false);
}

var element = angular.element(event.currentTarget);

if (swipeOffset >= discussionOptionsWidth) {
element.css('right', discussionOptionsWidth + 'px');
} else if (swipeOffset < 0) {
element.css('right', '0px');
} else {
element.css('right', swipeOffset + 'px');
}
}
};

$scope.onDragStop = function(event) {
var element = angular.element(event.currentTarget);

if (swipeOffset >= discussionOptionsWidth / 2) {
element.css('right', discussionOptionsWidth + 'px');
} else {
element.css('right', '0px');
}

if (swiping) {
$ionicScrollDelegate.freezeScroll(false);
$ionicSideMenuDelegate.canDragContent(true);
}

swiping = false;
pulling = false;
};

$scope.deleteDiscussion = function(discussion) {
var langKey = 'mma.messages.deletediscussionconfirmation';
$mmUtil.showConfirm($translate(langKey)).then(function() {
var modal = $mmUtil.showModalLoading('mm.core.deleting', true);
$mmaMessages.deleteDiscussion(discussion).then(function() {
$scope.discussions.splice($scope.discussions.indexOf(discussion), 1); // Remove discussion from the list without having to wait for re-fetch.
fetchDiscussions(); // Re-fetch discussions to update cached data.
}).catch(function(error) {
if (typeof error === 'string') {
$mmUtil.showErrorModal(error);
} else {
$mmUtil.showErrorModal('mma.messages.errordeletediscussion', true);
}
}).finally(function() {
modal.dismiss();
});
});
};
});

2 changes: 2 additions & 0 deletions www/addons/messages/lang/en.json
Expand Up @@ -7,6 +7,8 @@
"deletemessage": "Delete message",
"deletemessageconfirmation": "Are you sure you want to delete this message? It will only be deleted from your messaging history and will still be viewable by the user who sent or received the message.",
"errordeletemessage": "Error while deleting the message.",
"deletediscussionconfirmation": "Are you sure you want to delete this conversation? It will only be deleted from your messaging history and will still be viewable by the other user.",
"errordeletediscussion": "Error while deleting the conversation.",
"errorwhileretrievingcontacts": "Error while retrieving the contacts from the server.",
"errorwhileretrievingdiscussions": "Error while retrieving the discussions from the server.",
"errorwhileretrievingmessages": "Error while retrieving the messages from the server.",
Expand Down
42 changes: 42 additions & 0 deletions www/addons/messages/scss/styles.scss
Expand Up @@ -83,3 +83,45 @@ $mma-messages-date-badge: "stable" !default;
left: initial;
}
}

.mma-messages-discussions-item {
position: relative;

a {
z-index: 5;
}

.mma-messages-discussions-options {
position: absolute;
right: 0;
top: 0;
z-index: 3;
height: 100%;
margin: 0;
padding: 0;
list-style: none;

li {
display: block;
float: left;
height: 100%;
width: 50px;

button {
height: 100%;
width: 100%;
margin: 0;
border: none;
font-size: 20px;
}
}

.mma-messages-discussions-delete {
background-color: red;

i {
color: white;
}
}
}
}
79 changes: 79 additions & 0 deletions www/addons/messages/services/messages.js
Expand Up @@ -1036,5 +1036,84 @@ angular.module('mm.addons.messages')
});
};

/**
* Check if discussions can be deleted in current site.
*
* @module mm.addons.messages
* @ngdoc method
* @name $mmaMessages#canDeleteDiscussion
* @return {Boolean} True if can delete discussions, false otherwise.
*/
self.canDeleteDiscussion = function() {
return $mmSite.wsAvailable('core_message_delete_conversation')
&& $mmSite.wsAvailable('core_message_mark_all_messages_as_read');
};

/**
* Delete a discussion (online or offline).
*
* @module mm.addons.messages
* @ngdoc method
* @name $mmaMessages#deleteDiscussion
* @param {Object} discussion Discussion to delete.
* @return {Promise} Promise resolved when the discussion has been deleted.
*/
self.deleteDiscussion = function(discussion) {
// Need to mark messages as read, otherwise and empty discussion
// may show when refetching messages.
return self.markAllMessagesAsRead(discussion.message.user).then(function() {
return self.deleteDiscussionOnline(discussion.message.user).then(function() {
// Delete offline messages only if online deletion succeeded.
// This is to prevent the case where only offline messages (pending) are
// deleted, and online messages (sent) remain.
return $mmaMessagesOffline.deleteMessagesToUser(discussion.user);
});
});
};

/**
* Delete a discussion from the server.
*
* @module mm.addons.messages
* @ngdoc method
* @name $mmaMessages#deleteDiscussionOnline
* @param {Number} usertoId ID of user conversation is with.
* @param {Number} [userId] User we want to delete the conversation for. If not defined, use current user.
* @return {Promise} Promise resolved when the discussion has been deleted.
*/
self.deleteDiscussionOnline = function(usertoId, userId) {
userId = userId || $mmSite.getUserId();
var params = {
userid: userId,
otheruserid: usertoId
};
return $mmSite.write('core_message_delete_conversation', params).then(function() {
return self.invalidateDiscussionsCache();
});
};

/** Mark all messages in a discussion as read.
*
* @module mm.addons.messages
* @ngdoc method
* @name $mmaMessages#markAllMessagesAsRead
* @param {Number} usertoId ID of user discussion is with.
* @param {Number} [userId] User we want to mark the messages as read for. If not defined, use current user.
* @return {Promise} Promise resolved when the messages have been marked as read.
*/
self.markAllMessagesAsRead = function(usertoId, userId) {
userId = userId || $mmSite.getUserId();
var params = {
useridfrom: usertoId,
useridto: userId
};
var preSets = {
typeExpected: 'boolean'
};
return $mmSite.write('core_message_mark_all_messages_as_read', params, preSets).then(function() {
return self.invalidateDiscussionCache(userId);
});
};

return self;
});
35 changes: 35 additions & 0 deletions www/addons/messages/services/messages_offline.js
Expand Up @@ -75,6 +75,41 @@ angular.module('mm.addons.messages')
});
};

/**
* Delete all messages sent to a user.
*
* @module mm.addons.messages
* @ngdoc method
* @name $mmaMessagesOffline#deleteMessagesToUser
* @param {Number} to User ID the messages were sent to.
* @param {String} [siteId] Site ID. If not defined, current site.
* @return {Promise} Promise resolved if deleted, rejected if failure.
*/
self.deleteMessagesToUser = function(to, siteId) {
siteId = siteId || $mmSite.getId();

return $mmSitesManager.getSite(siteId).then(function(site) {
var db = site.getDb();

return db.whereEqual(mmaMessagesOfflineMessagesStore, 'touserid', to).then(function(messages) {
if (messages && messages.length) {
return messages.reduce(function(promise, message) {
return promise.then(function() {
var id = [
message.touserid,
message.smallmessage,
message.timecreated
];
return db.remove(mmaMessagesOfflineMessagesStore, id);
});
}, $q.when());
} else {
return $q.resolve();
}
});
});
};

/**
* Get all messages where deviceoffline is set to 1.
*
Expand Down
12 changes: 9 additions & 3 deletions www/addons/messages/templates/discussions.html
Expand Up @@ -2,16 +2,22 @@
<ion-refresher pulling-text="{{ 'mm.core.pulltorefresh' | translate }}" ng-if="loaded" on-refresh="refresh()"></ion-refresher>
<mm-loading hide-until="loaded">
<ul class="list">
<li>
<a class="item item-avatar" ng-repeat="disc in discussions | orderBy:'message.timecreated':true track by $index" mm-split-view-link="site.messages-discussion({userId: disc.message.user})" title="{{disc.fullname}}">

<li class="mma-messages-discussions-item" ng-repeat="disc in discussions | orderBy:'message.timecreated':true track by $index">
<a class="item item-avatar" on-touch="onDragStart($event)" on-drag="onDrag($event)" on-release="onDragStop($event)" mm-split-view-link="site.messages-discussion({userId: disc.message.user})" title="{{disc.fullname}}">
<img ng-src="{{disc.profileimageurl}}" alt="{{ 'mm.core.pictureof' | translate:{$a: disc.fullname} }}" role="presentation" mm-external-content ng-if="disc.profileimageurl">
<img src="img/user-avatar.png" alt="{{ 'mm.core.pictureof' | translate:{$a: disc.fullname} }}" role="presentation" ng-if="!disc.profileimageurl">

<span class="item-note" ng-if="disc.message.timecreated > 0">{{disc.message.timecreated / 1000 | mmDateDayOrTime}}</span>
<p class="item-heading">{{disc.fullname}}</p>
<p><mm-format-text watch="true" clean="true" singleline="true">{{disc.message.message | mmaMessagesFormat}}</mm-format-text></p>
</a>
<ul class="mma-messages-discussions-options">
<li ng-if="canDelete">
<button class="mma-messages-discussions-delete" ng-click="deleteDiscussion(disc)">
<i class="ion-minus-circled"></i>
</button>
</li>
</ul>
</li>
</ul>

Expand Down