Video support and pinch to zoom on images
This commit is contained in:
parent
0048af9b13
commit
e7db78274e
18 changed files with 274 additions and 94 deletions
|
@ -12,6 +12,8 @@
|
||||||
# The name of your application
|
# The name of your application
|
||||||
TARGET = harbour-tooter
|
TARGET = harbour-tooter
|
||||||
|
|
||||||
|
QT += network dbus sql
|
||||||
|
|
||||||
CONFIG += sailfishapp
|
CONFIG += sailfishapp
|
||||||
|
|
||||||
SOURCES += src/harbour-tooter.cpp \
|
SOURCES += src/harbour-tooter.cpp \
|
||||||
|
|
|
@ -116,7 +116,7 @@ var notificationGenerator = function(item){
|
||||||
var notification;
|
var notification;
|
||||||
switch (item.urgency){
|
switch (item.urgency){
|
||||||
case "normal":
|
case "normal":
|
||||||
notification = Qt.createQmlObject('import org.nemomobile.notifications 1.0; Notification { category: "x-nemo.example"; urgency: Notification.Normal; }', Qt.application, 'InternalQmlObject');
|
notification = Qt.createQmlObject('import org.nemomobile.notifications 1.0; Notification { category: "x-nemo.example"; urgency: Notification.Normal; }', Qt.application, 'InternalQmlObject');
|
||||||
break;
|
break;
|
||||||
case "critical":
|
case "critical":
|
||||||
notification = Qt.createQmlObject('import org.nemomobile.notifications 1.0; Notification { category: "x-nemo.example"; urgency: Notification.Critical; }', Qt.application, 'InternalQmlObject');
|
notification = Qt.createQmlObject('import org.nemomobile.notifications 1.0; Notification { category: "x-nemo.example"; urgency: Notification.Critical; }', Qt.application, 'InternalQmlObject');
|
||||||
|
@ -124,6 +124,7 @@ var notificationGenerator = function(item){
|
||||||
default:
|
default:
|
||||||
notification = Qt.createQmlObject('import org.nemomobile.notifications 1.0; Notification { category: "x-nemo.example"; urgency: Notification.Low; }', Qt.application, 'InternalQmlObject');
|
notification = Qt.createQmlObject('import org.nemomobile.notifications 1.0; Notification { category: "x-nemo.example"; urgency: Notification.Low; }', Qt.application, 'InternalQmlObject');
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.timestamp = item.timestamp
|
notification.timestamp = item.timestamp
|
||||||
notification.summary = item.summary
|
notification.summary = item.summary
|
||||||
notification.body = item.body
|
notification.body = item.body
|
||||||
|
@ -176,7 +177,7 @@ var notifier = function(item){
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(JSON.stringify(messageObject.data))
|
//console.log(JSON.stringify(messageObject.data))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notificationGenerator(msg)
|
notificationGenerator(msg)
|
||||||
|
|
|
@ -207,6 +207,7 @@ function getDate(dateStr){
|
||||||
function parseToot (data){
|
function parseToot (data){
|
||||||
//console.log(JSON.stringify(data))
|
//console.log(JSON.stringify(data))
|
||||||
var item = {};
|
var item = {};
|
||||||
|
|
||||||
item['type'] = "toot"
|
item['type'] = "toot"
|
||||||
item['highlight'] = false
|
item['highlight'] = false
|
||||||
item['status_id'] = data["id"]
|
item['status_id'] = data["id"]
|
||||||
|
|
|
@ -147,6 +147,7 @@ Page {
|
||||||
RemorseItem { id: remorse }
|
RemorseItem { id: remorse }
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
source: model.preview_url
|
source: model.preview_url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,117 +3,205 @@ import Sailfish.Silica 1.0
|
||||||
import QtMultimedia 5.0
|
import QtMultimedia 5.0
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
id: page
|
id: imagePage
|
||||||
property string type: ""
|
property string type: ""
|
||||||
property string previewURL: ""
|
property string previewURL: ""
|
||||||
property string mediaURL: ""
|
property string mediaURL: ""
|
||||||
allowedOrientations: Orientation.All
|
allowedOrientations: Orientation.All
|
||||||
Component.onCompleted: {
|
Component.onCompleted: function(){
|
||||||
console.log(type)
|
console.log(type)
|
||||||
console.log(previewURL)
|
console.log(previewURL)
|
||||||
console.log(mediaURL)
|
console.log(mediaURL)
|
||||||
}
|
if (type != 'gifv' && type != 'video') {
|
||||||
onStateChanged: {
|
imagePreview.source = mediaURL
|
||||||
if (status === PageStatus.Deactivating){
|
imageFlickable.visible = true;
|
||||||
video.stop()
|
} else {
|
||||||
}
|
video.source = mediaURL
|
||||||
if (status === PageStatus.Activating){
|
video.fillMode = VideoOutput.PreserveAspectFit
|
||||||
if (type !== "image" )
|
video.play()
|
||||||
video.play()
|
videoFlickable.visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BusyIndicator {
|
Flickable {
|
||||||
running: image.status !== Image.Ready
|
id: videoFlickable
|
||||||
size: BusyIndicatorSize.Large
|
visible: false
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
contentWidth: imageContainer.width; contentHeight: imageContainer.height
|
||||||
clip: true
|
clip: true
|
||||||
Image {
|
Image {
|
||||||
id: image
|
id: videoPreview
|
||||||
anchors.centerIn: parent
|
fillMode: Image.PreserveAspectFit
|
||||||
fillMode: Image.PreserveAspectCrop
|
anchors.fill: parent
|
||||||
asynchronous: true
|
source: previewURL
|
||||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
|
||||||
Behavior on opacity { FadeAnimator {} }
|
|
||||||
source: type === "image" ? mediaURL : previewURL
|
|
||||||
onStatusChanged: {
|
|
||||||
if (status === Image.Ready) {
|
|
||||||
console.log('Loaded')
|
|
||||||
width = sourceSize.width
|
|
||||||
height = sourceSize.height
|
|
||||||
if (width > height)
|
|
||||||
pinch.scale = page.width / width
|
|
||||||
else
|
|
||||||
pinch.scale = page.height / height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Video {
|
|
||||||
id: video
|
|
||||||
anchors.fill: parent
|
|
||||||
autoLoad: true
|
|
||||||
onStateChanged: {
|
|
||||||
switch(status){
|
|
||||||
case MediaPlayer.Loaded:
|
|
||||||
play();
|
|
||||||
break;
|
|
||||||
case MediaPlayer.Loading:
|
|
||||||
loader.running = true;
|
|
||||||
break;
|
|
||||||
case MediaPlayer.EndOfMedia:
|
|
||||||
if(seekable)
|
|
||||||
seek(0)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
loader.running = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
source: type !== "image" ? mediaURL : ""
|
|
||||||
onErrorStringChanged: {
|
|
||||||
console.log(errorString)
|
|
||||||
}
|
|
||||||
BusyIndicator {
|
|
||||||
id: loader
|
|
||||||
size: BusyIndicatorSize.Small
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: {
|
|
||||||
video.playbackState == MediaPlayer.PlayingState ? video.pause() : video.play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
focus: true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Video {
|
||||||
|
id: video
|
||||||
|
anchors.fill: parent
|
||||||
|
onPositionChanged: function(){
|
||||||
|
console.log(duration)
|
||||||
|
console.log(bufferProgress)
|
||||||
|
console.log(position)
|
||||||
|
progressRec.width = parent.width * position/duration
|
||||||
|
}
|
||||||
|
onStopped: function(){
|
||||||
|
play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: progressRec
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: 0
|
||||||
|
height: Theme.paddingSmall
|
||||||
|
color: Theme.highlightBackgroundColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flickable {
|
||||||
|
id: imageFlickable
|
||||||
|
visible: false
|
||||||
|
anchors.fill: parent
|
||||||
|
contentWidth: imageContainer.width; contentHeight: imageContainer.height
|
||||||
|
clip: true
|
||||||
|
onHeightChanged: if (imagePreview.status === Image.Ready) imagePreview.fitToScreen();
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: imageContainer
|
||||||
|
width: Math.max(imagePreview.width * imagePreview.scale, imageFlickable.width)
|
||||||
|
height: Math.max(imagePreview.height * imagePreview.scale, imageFlickable.height)
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: imagePreview
|
||||||
|
|
||||||
|
property real prevScale
|
||||||
|
|
||||||
|
function fitToScreen() {
|
||||||
|
scale = Math.min(imageFlickable.width / width, imageFlickable.height / height, 1)
|
||||||
|
pinchArea.minScale = scale
|
||||||
|
prevScale = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
cache: true
|
||||||
|
asynchronous: true
|
||||||
|
sourceSize.height: 1000;
|
||||||
|
smooth: false
|
||||||
|
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status == Image.Ready) {
|
||||||
|
fitToScreen()
|
||||||
|
loadedAnimation.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: loadedAnimation
|
||||||
|
target: imagePreview
|
||||||
|
property: "opacity"
|
||||||
|
duration: 250
|
||||||
|
from: 0; to: 1
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
|
||||||
|
onScaleChanged: {
|
||||||
|
if ((width * scale) > imageFlickable.width) {
|
||||||
|
var xoff = (imageFlickable.width / 2 + imageFlickable.contentX) * scale / prevScale;
|
||||||
|
imageFlickable.contentX = xoff - imageFlickable.width / 2
|
||||||
|
}
|
||||||
|
if ((height * scale) > imageFlickable.height) {
|
||||||
|
var yoff = (imageFlickable.height / 2 + imageFlickable.contentY) * scale / prevScale;
|
||||||
|
imageFlickable.contentY = yoff - imageFlickable.height / 2
|
||||||
|
}
|
||||||
|
prevScale = scale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PinchArea {
|
PinchArea {
|
||||||
id: pinch
|
id: pinchArea
|
||||||
visible: type === "image"
|
opacity: 0.3
|
||||||
|
property real minScale: 1.0
|
||||||
|
property real maxScale: 3.0
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
pinch.target: image
|
enabled: imagePreview.status === Image.Ready
|
||||||
pinch.minimumScale: 0.1
|
pinch.target: imagePreview
|
||||||
pinch.maximumScale: 10
|
pinch.minimumScale: minScale * 0.5 // This is to create "bounce back effect"
|
||||||
pinch.dragAxis: Pinch.XAndYAxis
|
pinch.maximumScale: maxScale * 1.5 // when over zoomed
|
||||||
}
|
|
||||||
Label {
|
onPinchFinished: {
|
||||||
visible: type !== "image"
|
imageFlickable.returnToBounds()
|
||||||
anchors {
|
if (imagePreview.scale < pinchArea.minScale) {
|
||||||
bottom: parent.bottom
|
bounceBackAnimation.to = pinchArea.minScale
|
||||||
left: parent.left
|
bounceBackAnimation.start()
|
||||||
right: parent.right
|
}
|
||||||
|
else if (imagePreview.scale > pinchArea.maxScale) {
|
||||||
|
bounceBackAnimation.to = pinchArea.maxScale
|
||||||
|
bounceBackAnimation.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
id: bounceBackAnimation
|
||||||
|
target: imagePreview
|
||||||
|
duration: 250
|
||||||
|
property: "scale"
|
||||||
|
from: imagePreview.scale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
sourceComponent: {
|
||||||
|
switch (imagePreview.status) {
|
||||||
|
case Image.Loading:
|
||||||
|
return loadingIndicator
|
||||||
|
case Image.Error:
|
||||||
|
return failedLoading
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
text: "Video playing is faulty... may break app... Just to know :)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loadingIndicator
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: childrenRect.height
|
||||||
|
width: imagePage.width
|
||||||
|
|
||||||
|
ProgressCircle {
|
||||||
|
id: imageLoadingIndicator
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
progressValue: imagePreview.progress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: failedLoading
|
||||||
|
Text {
|
||||||
|
font.pixelSize: Theme.fontSizeSmall;
|
||||||
|
text: qsTr("Error loading image")
|
||||||
|
color: Theme.highlightColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalScrollDecorator { flickable: imageFlickable }
|
||||||
|
IconButton {
|
||||||
|
visible: false
|
||||||
|
anchors{
|
||||||
|
right: imagePage.right;
|
||||||
|
rightMargin: Theme.paddingLarge;
|
||||||
|
bottom: imagePage.bottom;
|
||||||
|
bottomMargin: Theme.paddingLarge;
|
||||||
|
}
|
||||||
|
width: Theme.iconSizeMedium+Theme.paddingMedium*2
|
||||||
|
|
||||||
|
icon.source: "image://theme/icon-m-cloud-download"
|
||||||
|
onClicked: {
|
||||||
|
//py.saveImg(MD5.hex_md5(strThumbnailUrl),strHpTitle+"."+Script.parseDate(currentDay));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ Item {
|
||||||
opacity: 0.2
|
opacity: 0.2
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Theme.highlightDimmerColor
|
color: Theme.highlightDimmerColor
|
||||||
|
|
||||||
}
|
}
|
||||||
Image {
|
Image {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
|
@ -57,6 +57,19 @@ SilicaListView {
|
||||||
}
|
}
|
||||||
|
|
||||||
PullDownMenu {
|
PullDownMenu {
|
||||||
|
MenuItem {
|
||||||
|
text: "NOTIFIKACIJA"
|
||||||
|
onClicked: {
|
||||||
|
Logic.notifier({
|
||||||
|
type: "favourite",
|
||||||
|
urgency: "critical",
|
||||||
|
created_at: new Date(),
|
||||||
|
reblog_account_display_name: "@akakakak",
|
||||||
|
content: "blaaaaaa blaaaaaablaaaaaablaaaaaa"
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("Settings")
|
text: qsTr("Settings")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
|
|
@ -186,4 +186,5 @@ BackgroundItem {
|
||||||
type: "reply"
|
type: "reply"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,16 @@ BackgroundItem {
|
||||||
signal navigateTo(string link)
|
signal navigateTo(string link)
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: mnu.height + miniHeader.height + (typeof attachments !== "undefined" && attachments.count ? media.height + Theme.paddingLarge + Theme.paddingMedium: Theme.paddingLarge) + lblContent.height + Theme.paddingLarge + (ministatus.visible ? ministatus.height : 0)
|
height: mnu.height + miniHeader.height + (typeof attachments !== "undefined" && attachments.count ? media.height + Theme.paddingLarge + Theme.paddingMedium: Theme.paddingLarge) + lblContent.height + Theme.paddingLarge + (ministatus.visible ? ministatus.height : 0)
|
||||||
|
Rectangle {
|
||||||
|
x: 0;
|
||||||
|
y: 0;
|
||||||
|
visible: status_visibility == 'direct'
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
opacity: 0.3
|
||||||
|
color: Theme.highlightBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
MiniStatus {
|
MiniStatus {
|
||||||
id: ministatus
|
id: ministatus
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -284,4 +294,5 @@ BackgroundItem {
|
||||||
onDoubleClicked: {
|
onDoubleClicked: {
|
||||||
console.log("double click")
|
console.log("double click")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Κτυπήστε για εισαγωγή</translation>
|
<translation>Κτυπήστε για εισαγωγή</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Tap to insert</translation>
|
<translation>Tap to insert</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Toca para insertar</translation>
|
<translation>Toca para insertar</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Appuyez pour insérer</translation>
|
<translation>Appuyez pour insérer</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Tustejar per inserir</translation>
|
<translation>Tustejar per inserir</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Тапни за убацивање</translation>
|
<translation>Тапни за убацивање</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<translation>Tap to insert</translation>
|
<translation>Tap to insert</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ImageFullScreen</name>
|
||||||
|
<message>
|
||||||
|
<source>Error loading image</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImageUploader</name>
|
<name>ImageUploader</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
Loading…
Reference in a new issue