Browse Source

Supported message report

master
Igor Zhukov 5 years ago
parent
commit
63bc61bd32
  1. 60
      app/js/controllers.js
  2. 2
      app/js/lib/config.js
  3. 14
      app/js/lib/schema.tl
  4. 3
      app/js/lib/utils.js
  5. 12
      app/js/locales/en-us.json
  6. 34
      app/js/messages_manager.js
  7. 1
      app/partials/desktop/im.html
  8. 51
      app/partials/desktop/report_msgs_modal.html
  9. 1
      app/partials/mobile/message_actions_modal.html

60
app/js/controllers.js

@ -511,6 +511,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -511,6 +511,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
canReply: false,
canDelete: false,
canEdit: false,
canReport: false,
actions: function () {
return $scope.historyState.selectActions ? 'selected' : ($scope.historyState.botActions ? 'bot' : ($scope.historyState.channelActions ? 'channel' : false))
},
@ -1246,6 +1247,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1246,6 +1247,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.selectedEdit = selectedEdit
$scope.selectedCancel = selectedCancel
$scope.selectedFlush = selectedFlush
$scope.selectedReport = selectedReport
$scope.selectInlineBot = selectInlineBot
$scope.startBot = startBot
@ -1755,6 +1757,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1755,6 +1757,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
if (Config.Mobile) {
$scope.historyState.canEdit = AppMessagesManager.canEditMessage(messageID)
$scope.historyState.canReport = AppMessagesManager.canReportMessage(messageID)
$modal.open({
templateUrl: templateUrl('message_actions_modal'),
@ -1778,6 +1781,10 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1778,6 +1781,10 @@ angular.module('myApp.controllers', ['myApp.i18n'])
selectedForward(messageID)
break
case 'report':
selectedReport(messageID)
break
case 'select':
$scope.historyState.selectActions = 'selected'
$scope.$broadcast('ui_panel_update')
@ -1837,6 +1844,15 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1837,6 +1844,15 @@ angular.module('myApp.controllers', ['myApp.i18n'])
if ($scope.selectedCount == 1) {
angular.forEach($scope.selectedMsgs, function (t, messageID) {
$scope.historyState.canEdit = AppMessagesManager.canEditMessage(messageID)
$scope.historyState.canReport = AppMessagesManager.canReportMessage(messageID)
})
} else {
$scope.historyState.canEdit = false
$scope.historyState.canReport = false
angular.forEach($scope.selectedMsgs, function (t, messageID) {
if (AppMessagesManager.canReportMessage(messageID)) {
$scope.historyState.canReport = true
}
})
}
$scope.$broadcast('messages_select')
@ -1979,6 +1995,38 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1979,6 +1995,38 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}
}
function selectedReport (selectedMessageID) {
var selectedMessageIDs = []
if (selectedMessageID) {
selectedMessageIDs.push(selectedMessageID)
} else if ($scope.selectedCount > 0) {
angular.forEach($scope.selectedMsgs, function (t, messageID) {
selectedMessageIDs.push(messageID)
})
}
if (selectedMessageIDs.length) {
$modal.open({
templateUrl: templateUrl('report_msgs_modal'),
controller: 'ReportMessagesModalController',
windowClass: 'md_simple_modal_window mobile_modal',
scope: $scope.$new()
}).result.then(function (inputReason) {
selectedCancel()
AppMessagesManager.reportMessages(selectedMessageIDs, inputReason).then(function () {
var toastData = toaster.pop({
type: 'info',
body: _('confirm_modal_report_success'),
bodyOutputType: 'trustedHtml',
clickHandler: function () {
toaster.clear(toastData)
},
showCloseButton: false
})
})
})
}
}
function selectedReply (selectedMessageID) {
if (!selectedMessageID && $scope.selectedCount == 1) {
angular.forEach($scope.selectedMsgs, function (t, messageID) {
@ -4503,6 +4551,18 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -4503,6 +4551,18 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}
})
.controller('ReportMessagesModalController', function ($scope, $modalInstance) {
$scope.reason = {_: 'inputReportReasonSpam', text: ''}
$scope.toggleReportReason = function (reason) {
$scope.reason = {_: reason}
if (reason == 'inputReportReasonOther') {
onContentLoaded(function () {
$scope.$broadcast('ui_reason_text_focus')
})
}
}
})
.controller('ProfileEditModalController', function ($scope, $modalInstance, AppUsersManager, MtpApiManager) {
$scope.profile = {}
$scope.error = {}

2
app/js/lib/config.js

File diff suppressed because one or more lines are too long

14
app/js/lib/schema.tl

@ -106,7 +106,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto; @@ -106,7 +106,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
@ -174,7 +174,6 @@ inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags @@ -174,7 +174,6 @@ inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings;
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
@ -185,6 +184,7 @@ wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; @@ -185,6 +184,7 @@ wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
inputReportReasonPornography#2e59d922 = ReportReason;
inputReportReasonChildAbuse#adf44ee3 = ReportReason;
inputReportReasonOther#e1746d0a text:string = ReportReason;
userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull;
@ -423,7 +423,7 @@ accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; @@ -423,7 +423,7 @@ accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
@ -578,7 +578,7 @@ botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo @@ -578,7 +578,7 @@ botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo
messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;
exportedMessageLink#1f486803 link:string = ExportedMessageLink;
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
@ -821,7 +821,6 @@ auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:strin @@ -821,7 +821,6 @@ auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:strin
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool;
auth.resetAuthorizations#9fab0d1a = Bool;
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
@ -833,7 +832,7 @@ auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentC @@ -833,7 +832,7 @@ auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentC
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
account.registerDevice#01280460 token_type:int token:string app_sandbox:Bool other_uids:Vector<int> = Bool;
account.registerDevice#1389cc token_type:int token:string app_sandbox:Bool other_uids:Vector<int> = Bool;
account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool;
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
@ -895,6 +894,7 @@ messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6 @@ -895,6 +894,7 @@ messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.hideReportSpam#a8f1709b peer:InputPeer = Bool;
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
messages.editChatTitle#dc452855 chat_id:int title:string = Updates;
@ -902,7 +902,6 @@ messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; @@ -902,7 +902,6 @@ messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates;
messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates;
messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
@ -915,6 +914,7 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da @@ -915,6 +914,7 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;

3
app/js/lib/utils.js

@ -394,7 +394,8 @@ function templateUrl (tplName) { @@ -394,7 +394,8 @@ function templateUrl (tplName) {
megagroup_edit_modal: 'desktop',
inline_results: 'desktop',
composer_dropdown: 'desktop',
peer_pinned_message_bar: 'desktop'
peer_pinned_message_bar: 'desktop',
report_msgs_modal: 'desktop'
}
var layout = forceLayout[tplName] || (Config.Mobile ? 'mobile' : 'desktop')
return 'partials/' + layout + '/' + tplName + '.html'

12
app/js/locales/en-us.json

@ -219,6 +219,15 @@ @@ -219,6 +219,15 @@
"group_invite_revoke_active": "Revoking...",
"group_invite_revoke": "Revoke",
"report_reason_modal_title": "Report",
"report_reason_modal_spam": "Spam",
"report_reason_modal_violence": "Violence",
"report_reason_modal_pornography": "Pornography",
"report_reason_modal_childabuse": "Child Abuse",
"report_reason_modal_other": "Other",
"report_reason_modal_other_placeholder": "Description",
"report_reason_modal_submit_btn": "Send",
"clipboard_copied": "Copied!",
"clipboard_press_ctrl_c": "Press Ctrl+C to copy",
"clipboard_press_cmd_c": "Press ⌘+C to copy",
@ -246,6 +255,7 @@ @@ -246,6 +255,7 @@
"confirm_modal_login_phone_correct": "Is this phone number correct?",
"confirm_modal_forward_to_peer": "Forward to {peer}?",
"confirm_modal_forward_to_peer_success": "Message was successfully forwarded.",
"confirm_modal_report_success": "Report sent",
"confirm_modal_send_to_peer": "Send to {peer}?",
"confirm_modal_share_file_peer": "Share with {peer}?",
"confirm_modal_invite_peer": "Invite to {peer}?",
@ -391,6 +401,7 @@ @@ -391,6 +401,7 @@
"message_action_reply": "Reply",
"message_action_edit": "Edit",
"message_action_delete": "Delete",
"message_action_report": "Report",
"message_action_forward": "Forward",
"message_action_select": "Select",
"message_action_cancel": "Cancel",
@ -529,6 +540,7 @@ @@ -529,6 +540,7 @@
"im_channel_join": "+ Join",
"im_channel_mute": "Mute",
"im_channel_unmute": "Unmute",
"im_report": "Report {count}",
"im_reply_loading": "Loading{dots}",
"im_X_forwarded_messages": "{'one': '{} forwarded message', 'other': '{} forwarded messages'}",
"im_photos_drop_text": "Drop photos here to send",

34
app/js/messages_manager.js

@ -1013,6 +1013,19 @@ angular.module('myApp.services') @@ -1013,6 +1013,19 @@ angular.module('myApp.services')
return true
}
function canReportMessage(messageID) {
if (!messagesStorage[messageID]) {
return false
}
if (!canEditMessage(messageID)) {
var message = messagesStorage[messageID]
if (!message.pFlags.out) {
return true
}
}
return false
}
function getMessageEditData(messageID) {
if (!canEditMessage(messageID)) {
return $q.reject()
@ -2177,6 +2190,25 @@ angular.module('myApp.services') @@ -2177,6 +2190,25 @@ angular.module('myApp.services')
return $q.all(promises)
}
function reportMessages (mids, reason) {
mids = mids.sort()
var splitted = AppMessagesIDsManager.splitMessageIDsByChannels(mids)
var promises = []
angular.forEach(splitted.msgIDs, function (msgIDs, channelID) {
var peerID = -channelID || getMessagePeer(getMessage(msgIDs[0]))
var promise = MtpApiManager.invokeApi('messages.report', {
peer: AppPeersManager.getInputPeerByID(peerID),
id: msgIDs,
reason: reason
}).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates)
})
promises.push(promise)
})
return $q.all(promises)
}
function startBot (botID, chatID, startParam) {
var peerID = chatID ? -chatID : botID
if (startParam) {
@ -3847,6 +3879,7 @@ angular.module('myApp.services') @@ -3847,6 +3879,7 @@ angular.module('myApp.services')
sendFile: sendFile,
sendOther: sendOther,
forwardMessages: forwardMessages,
reportMessages: reportMessages,
startBot: startBot,
shareGame: shareGame,
editMessage: editMessage,
@ -3856,6 +3889,7 @@ angular.module('myApp.services') @@ -3856,6 +3889,7 @@ angular.module('myApp.services')
getMessageShareLink: getMessageShareLink,
canMessageBeEdited: canMessageBeEdited,
canEditMessage: canEditMessage,
canReportMessage: canReportMessage,
getMessageEditData: getMessageEditData,
canRevokeMessage: canRevokeMessage,
clearDialogCache: clearDialogCache,

1
app/partials/desktop/im.html

@ -200,6 +200,7 @@ @@ -200,6 +200,7 @@
<a class="btn btn-md btn-md-primary im_edit_cancel_link" ng-click="selectedCancel()" my-i18n="modal_cancel"></a>
<a class="btn btn-primary im_edit_forward_btn" ng-click="selectedForward()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount" my-i18n-format="im_forward"></a>
<a class="btn btn-primary im_edit_delete_btn" ng-click="selectedDelete()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount" my-i18n-format="im_delete" ng-show="historyState.canDelete"></a>
<a class="btn btn-primary im_edit_delete_btn" ng-click="selectedReport()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount" my-i18n-format="im_report" ng-show="historyState.canReport"></a>
<a class="btn btn-primary im_edit_reply_btn" ng-click="selectedReply()" ng-show="selectedCount == 1 &amp;&amp; historyState.canReply" my-i18n="im_reply"></a>
<a class="btn btn-primary im_edit_reply_btn" ng-click="selectedEdit()" ng-show="selectedCount == 1 &amp;&amp; historyState.canEdit" my-i18n="im_edit"></a>
<my-i18n-param name="count"><strong class="im_selected_count" ng-show="selectedCount > 0" ng-bind="selectedCount"></strong></my-i18n-param>

51
app/partials/desktop/report_msgs_modal.html

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
<div class="md_simple_modal_wrap" my-modal-position>
<div class="md_simple_modal_body">
<form class="modal_simple_form" ng-submit="$close(reason)">
<h4 my-i18n="report_reason_modal_title"></h4>
<div class="tg_radios_wrap">
<a class="md_modal_section_radio_wrap tg_radio" ng-click="toggleReportReason('inputReportReasonSpam')" ng-class="reason._ == 'inputReportReasonSpam' ? 'tg_radio_on' : ''">
<span class="icon icon-radio-outer"><i class="icon-radio"></i></span>
<span my-i18n="report_reason_modal_spam"></span>
</a>
<a class="md_modal_section_radio_wrap tg_radio" ng-click="toggleReportReason('inputReportReasonViolence')" ng-class="reason._ == 'inputReportReasonViolence' ? 'tg_radio_on' : ''">
<span class="icon icon-radio-outer"><i class="icon-radio"></i></span>
<span my-i18n="report_reason_modal_violence"></span>
</a>
<a class="md_modal_section_radio_wrap tg_radio" ng-click="toggleReportReason('inputReportReasonChildAbuse')" ng-class="reason._ == 'inputReportReasonChildAbuse' ? 'tg_radio_on' : ''">
<span class="icon icon-radio-outer"><i class="icon-radio"></i></span>
<span class="" my-i18n="report_reason_modal_childabuse"></span>
</a>
<a class="md_modal_section_radio_wrap tg_radio" ng-click="toggleReportReason('inputReportReasonPornography')" ng-class="reason._ == 'inputReportReasonPornography' ? 'tg_radio_on' : ''">
<span class="icon icon-radio-outer"><i class="icon-radio"></i></span>
<span my-i18n="report_reason_modal_pornography"></span>
</a>
<a class="md_modal_section_radio_wrap tg_radio" ng-click="toggleReportReason('inputReportReasonOther')" ng-class="reason._ == 'inputReportReasonOther' ? 'tg_radio_on' : ''">
<span class="icon icon-radio-outer"><i class="icon-radio"></i></span>
<span my-i18n="report_reason_modal_other"></span>
</a>
</div>
<div class="md-input-group" my-labeled-input ng-show="reason._ == 'inputReportReasonOther'">
<label class="md-input-label" my-i18n="report_reason_modal_other_placeholder"></label>
<input class="md-input" my-focus-on="ui_reason_text_focus" type="text" ng-model="reason.text" />
</div>
</form>
</div>
<div class="md_simple_modal_footer">
<button class="btn btn-md" ng-click="$dismiss()" my-i18n="modal_cancel"></button>
<button class="btn btn-md btn-md-primary" ng-click="$close(reason)" my-i18n="report_reason_modal_submit_btn"></button>
</div>
</div>

1
app/partials/mobile/message_actions_modal.html

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
<button ng-if="historyState.canEdit" class="btn btn-md btn-md-primary btn-block" my-i18n="message_action_edit" ng-click="$close('edit')"></button>
<button class="btn btn-md btn-md-primary btn-block" my-i18n="message_action_forward" ng-click="$close('forward')"></button>
<button ng-if="historyState.canDelete" class="btn btn-md btn-md-primary btn-block" my-i18n="message_action_delete" ng-click="$close('delete')"></button>
<button ng-if="historyState.canReport" class="btn btn-md btn-md-primary btn-block" my-i18n="message_action_report" ng-click="$close('report')"></button>
<button class="btn btn-md btn-md-primary btn-block" my-i18n="message_action_select" ng-click="$close('select')"></button>
<button class="btn btn-md btn-block" my-i18n="message_action_cancel" ng-click="$dismiss()"></button>
</div>

Loading…
Cancel
Save