Browse Source

Download videos, attach tooltips

master
Igor Zhukov 10 years ago
parent
commit
37cebdb237
  1. 82
      app/css/app.css
  2. BIN
      app/img/icons/IconsetW.png
  3. BIN
      app/img/icons/IconsetW_1x.png
  4. 12
      app/js/controllers.js
  5. 94
      app/js/services.js
  6. 28
      app/partials/im.html
  7. 55
      app/partials/message.html

82
app/css/app.css

@ -256,7 +256,7 @@ input[type="number"]::-webkit-inner-spin-button { @@ -256,7 +256,7 @@ input[type="number"]::-webkit-inner-spin-button {
vertical-align: text-top;
background: url(../img/icons/IconsetW.png) -15px -419px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.6;
}
.is_1x .icon-back {
@ -518,7 +518,7 @@ input[type="number"]::-webkit-inner-spin-button { @@ -518,7 +518,7 @@ input[type="number"]::-webkit-inner-spin-button {
font-size: 12px;
line-height: normal;
background: #F2F2F2 url(../img/icons/IconsetW.png) -6px -205px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
border: 1px solid #F2F2F2;
border-radius: 3px;
padding: 6px 20px 6px 30px;
@ -542,7 +542,7 @@ input[type="number"]::-webkit-inner-spin-button { @@ -542,7 +542,7 @@ input[type="number"]::-webkit-inner-spin-button {
height: 13px;
vertical-align: text-top;
background: url(../img/icons/IconsetW.png) -15px -192px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.6;
}
.is_1x .im_dialogs_search_clear {
@ -795,7 +795,7 @@ a.im_dialog:hover .im_dialog_date { @@ -795,7 +795,7 @@ a.im_dialog:hover .im_dialog_date {
margin-left: 6px;
background: url(../img/icons/IconsetW.png) -17px -444px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
}
.is_1x .icon-caret {
background-image: url(../img/icons/IconsetW_1x.png);
@ -961,7 +961,6 @@ a.im_message_contact_photo { @@ -961,7 +961,6 @@ a.im_message_contact_photo {
a.im_message_photo_thumb,
a.im_message_video_thumb {
display: block;
margin-top: 5px;
overflow: hidden;
border-radius: 2px;
}
@ -970,6 +969,15 @@ img.im_message_video_thumb { @@ -970,6 +969,15 @@ img.im_message_video_thumb {
overflow: hidden;
border-radius: 2px;
}
.im_message_video,
a.im_message_photo_thumb {
margin-top: 5px;
}
a.im_message_video_thumb {
float: left;
margin-right: 15px;
position: relative;
}
img.im_message_video_thumb {
-webkit-filter: blur(2px);
@ -983,21 +991,36 @@ img.im_message_video_thumb { @@ -983,21 +991,36 @@ img.im_message_video_thumb {
div.im_message_video_thumb {
position: relative;
}
.im_message_video_duration_wrap {
background: rgba(0, 0, 0, 0.5);
.im_message_video_duration {
background: rgba(0, 0, 0, 0.4);
color: #FFF;
position: absolute;
margin-top: -15px;
height: 15px;
padding: 0 3px;
bottom: 4px;
right: 4px;
padding: 2px 6px;
font-size: 11px;
line-height: 15px;
border-radius: 0 0 2px 2px;
border-radius: 2px;
overflow: hidden;
z-index: 1;
}
.im_message_video_duration {
.icon-videoplay {
position: absolute;
display: inline-block;
top: 50%;
left: 50%;
margin-left: -21px;
margin-top: -21px;
width: 42px;
height: 42px;
background: url(../img/icons/IconsetW.png) 0 -590px no-repeat;
background-size: 42px 680px;
z-index: 1;
}
.is_1x .icon-videoplay {
background-image: url(../img/icons/IconsetW_1x.png);
}
.im_message_geopoint {
@ -1020,7 +1043,7 @@ div.im_message_video_thumb { @@ -1020,7 +1043,7 @@ div.im_message_video_thumb {
height: 19px;
background: url(../img/icons/IconsetW.png) -14px -389px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
}
.is_1x .icon-geo-point {
background-image: url(../img/icons/IconsetW_1x.png);
@ -1048,7 +1071,7 @@ div.im_message_video_thumb { @@ -1048,7 +1071,7 @@ div.im_message_video_thumb {
vertical-align: text-top;
background: #F2F2F2 url(../img/icons/IconsetW.png) -2px -229px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
border-radius: 3px;
margin-right: 10px;
}
@ -1135,7 +1158,7 @@ img.im_message_document_thumb { @@ -1135,7 +1158,7 @@ img.im_message_document_thumb {
vertical-align: text-top;
background: #F2F2F2 url(../img/icons/IconsetW.png) -2px -277px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
border-radius: 3px;
margin-right: 10px;
}
@ -1189,6 +1212,13 @@ img.im_message_document_thumb { @@ -1189,6 +1212,13 @@ img.im_message_document_thumb {
.im_message_document_thumbed .im_message_document_name {
max-width: 150px;
}
.im_message_video .im_message_document_name_wrap,
.im_message_video .im_message_download_progress_wrap {
width: 150px;
}
.im_message_video .im_message_document_name_wrap {
margin-top: 5px;
}
.tg_up_progress,
.tg_down_progress {
@ -1404,7 +1434,7 @@ textarea.im_message_field { @@ -1404,7 +1434,7 @@ textarea.im_message_field {
height: 23px;
vertical-align: text-top;
background: url(../img/icons/IconsetW.png) -12px -68px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.8;
}
.is_1x .icon-paperclip {
@ -1432,7 +1462,7 @@ textarea.im_message_field { @@ -1432,7 +1462,7 @@ textarea.im_message_field {
height: 23px;
vertical-align: text-top;
background: url(../img/icons/IconsetW.png) -10px -4px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.8;
}
.is_1x .icon-emoji {
@ -1482,7 +1512,7 @@ textarea.im_message_field { @@ -1482,7 +1512,7 @@ textarea.im_message_field {
height: 21px;
vertical-align: text-top;
background: url(../img/icons/IconsetW.png) -9px -132px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.8;
}
.is_1x .icon-camera {
@ -1905,7 +1935,7 @@ img.img_fullsize { @@ -1905,7 +1935,7 @@ img.img_fullsize {
.emoji-menu-tail {
display: none;
background: url(../img/icons/IconsetW.png) -14px -268px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
width: 14px;
height: 7px;
margin: 0 83px;
@ -2050,7 +2080,7 @@ img.img_fullsize { @@ -2050,7 +2080,7 @@ img.img_fullsize {
font-size: 12px;
line-height: normal;
background: #F2F2F2 url(../img/icons/IconsetW.png) -6px -205px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
border: 1px solid #F2F2F2;
border-radius: 3px;
padding: 6px 20px 6px 30px;
@ -2074,7 +2104,7 @@ img.img_fullsize { @@ -2074,7 +2104,7 @@ img.img_fullsize {
height: 13px;
vertical-align: text-top;
background: url(../img/icons/IconsetW.png) -15px -192px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.6;
}
.is_1x .contacts_modal_search_clear {
@ -2151,7 +2181,7 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status { @@ -2151,7 +2181,7 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status {
width: 17px;
height: 15px;
background: url(../img/icons/IconsetW.png) -13px -366px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
opacity: 0.5;
}
.is_1x .icon-contact-tick {
@ -2249,7 +2279,7 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status { @@ -2249,7 +2279,7 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status {
height: 15px;
background: url(../img/icons/IconsetW.png) -15px -319px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
}
.is_1x .icon-delete {
background-image: url(../img/icons/IconsetW_1x.png);
@ -2296,7 +2326,7 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status { @@ -2296,7 +2326,7 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status {
height: 26px;
margin: 13px 0 0 40px;
background: url(../img/icons/IconsetW.png) -9px -516px no-repeat;
background-size: 42px 620px;
background-size: 42px 680px;
}
.is_1x .icon-select-tick {
background-image: url(../img/icons/IconsetW_1x.png);
@ -2531,4 +2561,4 @@ ce671b orange @@ -2531,4 +2561,4 @@ ce671b orange
color: #999;
font-size: 13px;
margin-left: 8px;
}
}

BIN
app/img/icons/IconsetW.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
app/img/icons/IconsetW_1x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

12
app/js/controllers.js

@ -623,7 +623,11 @@ angular.module('myApp.controllers', []) @@ -623,7 +623,11 @@ angular.module('myApp.controllers', [])
$scope.$on('history_append', function (e, addedMessage) {
if (addedMessage.peerID == $scope.curDialog.peerID) {
if ($scope.mediaType) {
$scope.missedCount++;
if (addedMessage.my) {
toggleMedia();
} else {
$scope.missedCount++;
}
return;
}
// console.log('append', addedMessage);
@ -665,6 +669,12 @@ angular.module('myApp.controllers', []) @@ -665,6 +669,12 @@ angular.module('myApp.controllers', [])
}
});
$scope.$on('history_focus', function (e, peerData) {
if ($scope.mediaType) {
toggleMedia();
}
});
$scope.$on('apiUpdate', function (e, update) {
// console.log('on apiUpdate inline', update);
switch (update._) {

94
app/js/services.js

@ -1827,8 +1827,9 @@ angular.module('myApp.services', []) @@ -1827,8 +1827,9 @@ angular.module('myApp.services', [])
})
.service('AppVideoManager', function ($rootScope, $modal, $window, MtpApiFileManager, AppUsersManager) {
.service('AppVideoManager', function ($rootScope, $modal, $window, $timeout, MtpApiFileManager, AppUsersManager) {
var videos = {};
var videosForHistory = {};
function saveVideo (apiVideo) {
videos[apiVideo.id] = apiVideo;
@ -1844,6 +1845,10 @@ angular.module('myApp.services', []) @@ -1844,6 +1845,10 @@ angular.module('myApp.services', [])
};
function wrapForHistory (videoID) {
if (videosForHistory[videoID] !== undefined) {
return videosForHistory[videoID];
}
var video = angular.copy(videos[videoID]),
width = 200,
height = 200,
@ -1867,7 +1872,7 @@ angular.module('myApp.services', []) @@ -1867,7 +1872,7 @@ angular.module('myApp.services', [])
video.thumb = thumb;
return video;
return videosForHistory[videoID] = video;
}
function wrapForFull (videoID) {
@ -1915,7 +1920,76 @@ angular.module('myApp.services', []) @@ -1915,7 +1920,76 @@ angular.module('myApp.services', [])
});
}
function downloadVideo (videoID, accessHash, popup) {
var video = videos[videoID],
historyVideo = videosForHistory[videoID] || video || {},
inputFileLocation = {
_: 'inputVideoFileLocation',
id: videoID,
access_hash: accessHash || video.access_hash
};
historyVideo.progress = {enabled: true, percent: 1, total: video.size};
function updateDownloadProgress (progress) {
console.log('dl progress', progress);
historyVideo.progress.done = progress.done;
historyVideo.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total));
$rootScope.$broadcast('history_update');
}
var ext = 'mp4',
mimeType = 'video/mpeg4',
fileName = 'video' + videoID + '.' + ext;
if (window.chrome && chrome.fileSystem && chrome.fileSystem.chooseEntry) {
chrome.fileSystem.chooseEntry({
type: 'saveFile',
suggestedName: fileName,
accepts: [{
mimeTypes: [mimeType],
extensions: [ext]
}]
}, function (writableFileEntry) {
MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, writableFileEntry, {mime: mimeType}).then(function (url) {
delete historyVideo.progress;
console.log('file save done');
}, function (e) {
console.log('video download failed', e);
historyVideo.progress.enabled = false;
}, updateDownloadProgress);
});
} else {
MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, null, {mime: mimeType}).then(function (url) {
delete historyVideo.progress;
if (popup) {
window.open(url, '_blank');
return
}
var a = $('<a>Download</a>')
.css({position: 'absolute', top: 1, left: 1})
.attr('href', url)
.attr('target', '_blank')
.attr('download', fileName)
.appendTo('body');
a[0].dataset.downloadurl = [mimeType, fileName, url].join(':');
a[0].click();
$timeout(function () {
a.remove();
}, 100);
}, function (e) {
console.log('video download failed', e);
historyVideo.progress.enabled = false;
}, updateDownloadProgress);
}
};
$rootScope.openVideo = openVideo;
$rootScope.downloadVideo = downloadVideo;
return {
saveVideo: saveVideo,
@ -1977,7 +2051,7 @@ angular.module('myApp.services', []) @@ -1977,7 +2051,7 @@ angular.module('myApp.services', [])
return docsForHistory[docID] = doc;
}
function openDoc (docID, accessHash, popup) {
function downloadDoc (docID, accessHash, popup) {
var doc = docs[docID],
historyDoc = docsForHistory[docID] || doc || {},
inputFileLocation = {
@ -2024,8 +2098,14 @@ angular.module('myApp.services', []) @@ -2024,8 +2098,14 @@ angular.module('myApp.services', [])
return
}
var a = $('<a>Download</a>').css({position: 'absolute', top: 1, left: 1}).attr('href', url).attr('target', '_blank').attr('download', doc.file_name).appendTo('body');
a[0].dataset.downloadurl = ['png', doc.file_name, url].join(':');
var a = $('<a>Download</a>')
.css({position: 'absolute', top: 1, left: 1})
.attr('href', url)
.attr('target', '_blank')
.attr('download', doc.file_name)
.appendTo('body');
a[0].dataset.downloadurl = [doc.mime_type, doc.file_name, url].join(':');
a[0].click();
$timeout(function () {
a.remove();
@ -2037,12 +2117,12 @@ angular.module('myApp.services', []) @@ -2037,12 +2117,12 @@ angular.module('myApp.services', [])
}
}
$rootScope.openDoc = openDoc;
$rootScope.downloadDoc = downloadDoc;
return {
saveDoc: saveDoc,
wrapForHistory: wrapForHistory,
openDoc: openDoc
downloadDoc: downloadDoc
}
})

28
app/partials/im.html

@ -118,7 +118,7 @@ @@ -118,7 +118,7 @@
</div>
<div class="im_history_typing_wrap">
<div class="im_history_typing" ng-show="typing.user">
<div class="im_history_typing" ng-show="typing.user &amp;&amp; !mediaType">
<strong class="im_history_typing_author" ng-bind-html="typing.user.rFullName"></strong> is typing<span my-typing-dots></span>
</div>
</div>
@ -175,22 +175,24 @@ @@ -175,22 +175,24 @@
<div class="im_send_dropbox_wrap"> Drop photos here to send </div>
<textarea ng-model="draftMessage.text" placeholder="Write a message..." class="form-control im_message_field"></textarea>
<div class="im_media_attach pull-right">
<input type="file" class="im_media_attach_input" size="28" multiple="true" accept="image/*, video/*, audio/*" />
<i class="icon icon-camera"></i>
</div>
<div class="" style="position: relative;">
<div class="im_media_attach pull-right" tooltip="Send media" tooltip-append-to-body="true">
<input type="file" class="im_media_attach_input" size="28" multiple="true" accept="image/*, video/*, audio/*" />
<i class="icon icon-camera"></i>
</div>
<div class="im_attach pull-right">
<input type="file" class="im_attach_input" size="28" multiple="true" />
<i class="icon icon-paperclip"></i>
</div>
<div class="im_attach pull-right" tooltip="Send file" tooltip-append-to-body="true">
<input type="file" class="im_attach_input" size="28" multiple="true" />
<i class="icon icon-paperclip"></i>
</div>
<div class="im_emoji_btn pull-right">
<i class="icon icon-emoji"></i>
</div>
<div class="im_emoji_btn pull-right">
<i class="icon icon-emoji"></i>
</div>
<button type="submit" class="btn btn-success im_submit">Send</button>
<button type="submit" class="btn btn-success im_submit">Send</button>
</div>
</form>
</div>

55
app/partials/message.html

@ -106,22 +106,47 @@ @@ -106,22 +106,47 @@
/>
</a>
<a ng-switch-when="messageMediaVideo" class="im_message_video_thumb" href="" ng-click="openVideo(historyMessage.media.video.id)" style="width: {{historyMessage.media.video.thumb.width}}px;">
<img
class="im_message_video_thumb"
my-load-thumb
thumb="historyMessage.media.video.thumb"
width="{{historyMessage.media.video.thumb.width}}"
height="{{historyMessage.media.video.thumb.height}}"
/>
<div class="im_message_video_duration_wrap" style="width: {{historyMessage.media.video.thumb.width}}px;">
<span class="im_message_video_duration pull-right">{{historyMessage.media.video.duration | duration}}</span>
<span class="glyphicon glyphicon-facetime-video"></span>
<div ng-switch-when="messageMediaVideo" class="im_message_video im_message_document_thumbed">
<a class="im_message_video_thumb" href="" ng-click="openVideo(historyMessage.media.video.id)" style="width: {{historyMessage.media.video.thumb.width}}px;">
<span class="im_message_video_duration">{{historyMessage.media.video.duration | duration}}</span>
<i class="icon icon-videoplay"></i>
<img
class="im_message_video_thumb"
my-load-thumb
thumb="historyMessage.media.video.thumb"
width="{{historyMessage.media.video.thumb.width}}"
height="{{historyMessage.media.video.thumb.height}}"
/>
</a>
<div class="im_message_document_info">
<div class="im_message_document_name_wrap">
<span class="im_message_document_name">Video</span>
<span class="im_message_document_size" ng-if="!historyMessage.media.video.progress.enabled">
{{historyMessage.media.video.size | formatSize}}
</span>
<span class="im_message_document_size" ng-if="historyMessage.media.video.progress.enabled">
{{historyMessage.media.video.progress | formatSizeProgress}}
</span>
</div>
<div class="im_message_document_actions" ng-if="!historyMessage.media.video.progress.enabled">
<a href="" ng-click="downloadVideo(historyMessage.media.video.id)">Download</a>
<a href="" ng-click="openVideo(historyMessage.media.video.id)">Play video</a>
</div>
<div class="im_message_download_progress_wrap" ng-if="historyMessage.media.video.progress.enabled">
<div class="progress tg_down_progress">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{historyMessage.media.video.progress.percent}}" aria-valuemin="0" aria-valuemax="100" style="width: {{historyMessage.media.video.progress.percent}}%">
<span class="sr-only">
{{historyMessage.media.video.progress.percent}}% Complete (success)
</span>
</div>
</div>
</div>
</div>
</a>
</div>
<div ng-switch-when="messageMediaDocument" class="im_message_document" ng-class="{im_message_document_thumbed: !!historyMessage.media.document.thumb}">
<a href="" ng-click="openDoc(historyMessage.media.document.id, false, historyMessage.media.document.withPreview)" ng-class="{im_message_document_link_disabled: historyMessage.media.document.progress.enabled}">
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, false, historyMessage.media.document.withPreview)" ng-class="{im_message_document_link_disabled: historyMessage.media.document.progress.enabled}">
<i class="icon icon-document" ng-if="!historyMessage.media.document.thumb"></i>
<div class="im_message_document_thumb_wrap" ng-if="historyMessage.media.document.thumb">
<img
@ -147,8 +172,8 @@ @@ -147,8 +172,8 @@
</span>
</div>
<div class="im_message_document_actions" ng-if="!historyMessage.media.document.progress.enabled">
<a href="" ng-click="openDoc(historyMessage.media.document.id)">Download</a>
<a href="" ng-click="openDoc(historyMessage.media.document.id, false, true)" ng-if="historyMessage.media.document.withPreview">Open</a>
<a href="" ng-click="downloadDoc(historyMessage.media.document.id)">Download</a>
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, false, true)" ng-if="historyMessage.media.document.withPreview">Open</a>
</div>
<div class="im_message_download_progress_wrap" ng-if="historyMessage.media.document.progress.enabled">
<div class="progress tg_down_progress">

Loading…
Cancel
Save