Merge pull request #1058 from G10h4ck/qml_app_development

Qml app improvements
This commit is contained in:
Gioacchino 2017-10-10 12:53:20 +02:00 committed by GitHub
commit 3b781f04dd
7 changed files with 202 additions and 167 deletions

View file

@ -28,7 +28,7 @@ Item
{ {
id: chatView id: chatView
property string chatId property string chatId
property var gxsInfo: "" property var gxsInfo: ({})
property int token: 0 property int token: 0
property string objectName:"chatView" property string objectName:"chatView"
@ -100,7 +100,7 @@ Item
anchors.fill: parent anchors.fill: parent
anchors.topMargin: parent.height / 2 anchors.topMargin: parent.height / 2
anchors.bottomMargin: categorySelectorHeight anchors.bottomMargin: if(!androidMode) categorySelectorHeight
property int categorySelectorHeight: 50 property int categorySelectorHeight: 50
@ -114,6 +114,7 @@ Item
name: "EMOJI_HIDDEN" name: "EMOJI_HIDDEN"
PropertyChanges { target: emojiPicker; anchors.topMargin: parent.height } PropertyChanges { target: emojiPicker; anchors.topMargin: parent.height }
PropertyChanges { target: emojiPicker; anchors.bottomMargin: -1 } PropertyChanges { target: emojiPicker; anchors.bottomMargin: -1 }
PropertyChanges { target: emojiPicker; height: 0 }
}, },
State { State {
name: "EMOJI_SHOWN" name: "EMOJI_SHOWN"
@ -132,7 +133,7 @@ Item
id: inferiorPanel id: inferiorPanel
height: ( msgComposer.height > styles.height)? msgComposer.height: styles.height height: ( msgComposer.height > styles.height)? msgComposer.height: styles.height
width: parent.width width: parent.width
anchors.bottom: parent.bottom anchors.bottom: emojiPicker.androidMode ? emojiPicker.top : parent.bottom
Rectangle Rectangle
{ {

View file

@ -50,7 +50,14 @@ Item
console.log("GxsIntentityDelegate onclicked:", model.name, console.log("GxsIntentityDelegate onclicked:", model.name,
model.gxs_id) model.gxs_id)
contactsView.searching = false contactsView.searching = false
if(model.own) contactsView.own_gxs_id = model.gxs_id if(model.own)
{
contactsView.own_gxs_id = model.gxs_id
stackView.push(
"qrc:/ContactDetails.qml",
{md: ChatCache.contactsCache.getContactFromGxsId(model.gxs_id)})
}
else else
{ {
startDistantChat() startDistantChat()

View file

@ -9,6 +9,8 @@
#include <QImageReader> #include <QImageReader>
#include <QBuffer> #include <QBuffer>
#include "qpainter.h"
#ifdef __ANDROID__ #ifdef __ANDROID__
# include <QtAndroid> # include <QtAndroid>
@ -41,14 +43,44 @@ public slots:
QString localPath = url.toLocalFile(); QString localPath = url.toLocalFile();
qDebug() << "imageToBase64() local path:" << localPath ; qDebug() << "imageToBase64() local path:" << localPath ;
QImage image= getImage (localPath);
// Read the image
QImageReader reader;
reader.setFileName(localPath);
QImage image = reader.read();
image = image.scaled(96,96,Qt::KeepAspectRatio,Qt::SmoothTransformation); image = image.scaled(96,96,Qt::KeepAspectRatio,Qt::SmoothTransformation);
qDebug() << "imageToBase64() encoding" ;
return imageToB64(image);
}
static QString b64AvatarGen (QVariantList onloads, int size)
{
qDebug() << "b64AvatarGen(): Generating face Avatar from";
QImage result(size, size, QImage::Format_ARGB32_Premultiplied);
QPainter painter(&result);
int counter = 0;
for (QVariantList::iterator j = onloads.begin(); j != onloads.end(); j++)
{
QImage image = getImage (":/"+(*j).toString());
painter.drawImage(0, 0, image); // xi, yi is the position for imagei
counter++;
}
painter.end();
return imageToB64(result);
}
static QImage getImage (QString const& path)
{
QImageReader reader;
reader.setFileName(path);
return reader.read();
}
static QString imageToB64 (QImage image)
{
// Transform image into PNG format // Transform image into PNG format
QByteArray ba; QByteArray ba;
QBuffer buffer( &ba ); QBuffer buffer( &ba );
@ -56,11 +88,8 @@ public slots:
image.save( &buffer, "png" ); image.save( &buffer, "png" );
// Get Based 64 image string // Get Based 64 image string
QString encoded = QString(ba.toBase64()); return QString(ba.toBase64());
qDebug() << "imageToBase64() encoded" ;
return encoded;
} }
}; };

View file

@ -4,64 +4,22 @@ import "../" // Needed by ChatCache (where stores generated faces)
Item Item
{ {
id: faces id: faces
property string hash property string hash
property var facesCache: ChatCache.facesCache property var facesCache: ChatCache.facesCache
Image Image
{ {
id: imageAvatar id: imageAvatar
width: height width: height
height: iconSize height: iconSize
visible: true
} }
Canvas Component.onCompleted: createFromHex(hash)
{
id: canvasAvatar
width: height
height: canvasSizes
visible: false
renderStrategy: Canvas.Threaded;
renderTarget: Canvas.Image;
property var images
property var callback
onPaint:
{
var ctx = getContext("2d");
if (images)
{
for (y = 0 ; y< nPieces ; y++)
{
ctx.drawImage(images[y], 0, 0, iconSize, iconSize )
}
}
}
onPainted:
{
if (callback)
{
var data = toDataURL('image/png')
callback(data)
}
}
}
Component.onCompleted:
{
createFromHex(hash)
}
/* TODO: Is there a reason why we are using var and not proper type for the
* following properties? */
property var facesPath: "/icons/faces/" property var facesPath: "/icons/faces/"
@ -134,11 +92,9 @@ Item
{ {
var url = src(gender, i, data[i+1]) var url = src(gender, i, data[i+1])
onloads.push(url) onloads.push(url)
canvasAvatar.loadImage(url)
} }
canvasAvatar.images = onloads var base64Image = androidImagePicker.b64AvatarGen(onloads, canvasSizes)
canvasAvatar.callback = callback callback("data:image/png;base64,"+base64Image)
canvasAvatar.requestPaint()
} }
// Create the identicon // Create the identicon
@ -146,30 +102,9 @@ Item
{ {
var iconId = [dataHex, iconSize]; var iconId = [dataHex, iconSize];
var update = function(data) var update = function(data)
{
// This conditions are for solve a bug on an Lg S3.
// On this device the toDataURL() is incompleted.
// So for see the complete avatar at least at first execution we'll show the canvas,
// instead of the image component.
// See issue: https://gitlab.com/angesoc/RetroShare/issues/37
if (facesCache.iconCache[iconId])
{ {
imageAvatar.source = data imageAvatar.source = data
imageAvatar.visible = true
canvasAvatar.visible = false
canvasAvatar.height = 0
imageAvatar.height = iconSize imageAvatar.height = iconSize
}
else
{
canvasAvatar.visible = true
imageAvatar.visible = false
canvasAvatar.height = iconSize
imageAvatar.height = 0
}
facesCache.iconCache[iconId] = data; facesCache.iconCache[iconId] = data;
} }

View file

@ -1,12 +1,14 @@
import QtQuick 2.7 import QtQuick 2.7
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.2
Rectangle { Rectangle
{
id: emojiButton id: emojiButton
property var fontName property var fontName
Text { Text
{
id: emojiText id: emojiText
color: "gray" color: "gray"
text: qsTr(eCatText) text: qsTr(eCatText)
@ -17,17 +19,22 @@ Rectangle {
state: "RELEASED" state: "RELEASED"
states: [ states:
State { [
State
{
name: "PRESSED" name: "PRESSED"
PropertyChanges { PropertyChanges
{
target: emojiText target: emojiText
font.pixelSize: emojiButton.width - 10 font.pixelSize: emojiButton.width - 10
} }
}, },
State { State
{
name: "RELEASED" name: "RELEASED"
PropertyChanges { PropertyChanges
{
target: emojiText target: emojiText
font.pixelSize: emojiButton.width - 8 font.pixelSize: emojiButton.width - 8
} }
@ -35,20 +42,25 @@ Rectangle {
] ]
MouseArea { MouseArea
{
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: { onEntered:
{
emojiText.color = "black" emojiText.color = "black"
} }
onExited: { onExited:
{
emojiText.color = "gray" emojiText.color = "gray"
} }
onPressedChanged: { onPressedChanged:
{
emojiButton.state = emojiButton.state == "PRESSED" ? "RELEASED" : "PRESSED" emojiButton.state = emojiButton.state == "PRESSED" ? "RELEASED" : "PRESSED"
} }
onClicked: { onClicked:
{
Qt.emojiClickedHandler(emojiText.text) Qt.emojiClickedHandler(emojiText.text)
} }
} }

View file

@ -1,30 +1,37 @@
import QtQuick 2.7 import QtQuick 2.7
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.2
Rectangle { Rectangle
{
id: emojiCategoryButton id: emojiCategoryButton
property string categoryName property string categoryName
property var fontName property var fontName
function completedHandler() { function completedHandler()
{
categoryName = eCatName categoryName = eCatName
//initialize //initialize
if (parent.currSelEmojiButton === undefined) { if (parent.currSelEmojiButton === undefined)
{
clickedHandler() clickedHandler()
} }
} }
function pressedHandler() { function pressedHandler()
if (state != "SELECTED") { {
if (state != "SELECTED")
{
state = state == "PRESSED" ? "RELEASED" : "PRESSED" state = state == "PRESSED" ? "RELEASED" : "PRESSED"
} }
} }
function clickedHandler() { function clickedHandler()
if (parent.currSelEmojiButton !== undefined) { {
if (parent.currSelEmojiButton !== undefined)
{
parent.currSelEmojiButton.state = "RELEASED" parent.currSelEmojiButton.state = "RELEASED"
} }
@ -34,7 +41,8 @@ Rectangle {
} }
Text { Text
{
id: emojiText id: emojiText
color: "gray" color: "gray"
text: qsTr(eCatText) text: qsTr(eCatText)
@ -45,31 +53,39 @@ Rectangle {
state: "RELEASED" state: "RELEASED"
states: [ states:
State { [
State
{
name: "PRESSED" name: "PRESSED"
PropertyChanges { PropertyChanges
{
target: emojiText target: emojiText
font.pixelSize: emojiCategoryButton.width - 10 font.pixelSize: emojiCategoryButton.width - 10
} }
}, },
State { State
{
name: "RELEASED" name: "RELEASED"
PropertyChanges { PropertyChanges
{
target: emojiText target: emojiText
font.pixelSize: emojiCategoryButton.width - 8 font.pixelSize: emojiCategoryButton.width - 8
} }
}, },
State { State
{
name: "SELECTED" name: "SELECTED"
PropertyChanges { PropertyChanges
{
target: emojiCategoryButton target: emojiCategoryButton
color: "#ADD6FF" color: "#ADD6FF"
} }
} }
] ]
MouseArea { MouseArea
{
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: emojiText.color = "black" onEntered: emojiText.color = "black"

View file

@ -2,33 +2,41 @@ import QtQuick 2.7
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import "emoji.js" as EmojiJSON import "emoji.js" as EmojiJSON
Rectangle { Rectangle
{
id: emojiPicker id: emojiPicker
property EmojiCategoryButton currSelEmojiButton property EmojiCategoryButton currSelEmojiButton
property variant emojiParsedJson property variant emojiParsedJson
property int buttonWidth: 40 property int buttonWidth: 40
property TextArea textArea property TextArea textArea
property bool androidMode: Qt.platform.os === "android" // On Desktop appears on top of text field, instead appears in place of virtual keyboard (under text field)
property var rootFontName: theme.emojiFontName property var rootFontName: theme.emojiFontName
//displays all Emoji of one categroy by modifying the ListModel of emojiGrid //displays all Emoji of one categroy by modifying the ListModel of emojiGrid
function categoryChangedHandler (newCategoryName){ function categoryChangedHandler (newCategoryName)
{
emojiByCategory.clear() emojiByCategory.clear()
for (var i = 0; i < emojiParsedJson.emoji_by_category[newCategoryName].length; i++) { for (var i = 0; i < emojiParsedJson.emoji_by_category[newCategoryName].length; i++)
{
var elem = emojiParsedJson.emoji_by_category[newCategoryName][i] var elem = emojiParsedJson.emoji_by_category[newCategoryName][i]
emojiByCategory.append({eCatName: newCategoryName, eCatText: elem}) emojiByCategory.append({eCatName: newCategoryName, eCatText: elem})
} }
} }
//adds the clicked Emoji (and one ' ' if the previous character isn't an Emoji) to textArea //adds the clicked Emoji (and one ' ' if the previous character isn't an Emoji) to textArea
function emojiClickedHandler(selectedEmoji) { function emojiClickedHandler(selectedEmoji)
{
var strAppnd = "" var strAppnd = ""
var plainText = textArea.getText(0, textArea.length) var plainText = textArea.getText(0, textArea.length)
if (plainText.length > 0) { if (plainText.length > 0) {
var lastChar = plainText[plainText.length-1] var lastChar = plainText[plainText.length-1]
if ((lastChar !== ' ') && (lastChar.charCodeAt(0) < 255)) { if ((lastChar !== ' ') && (lastChar.charCodeAt(0) < 255))
{
strAppnd = " " strAppnd = " "
} }
} }
@ -38,10 +46,12 @@ Rectangle {
} }
//parses JSON, publishes button handlers and inits textArea //parses JSON, publishes button handlers and inits textArea
function completedHandler() { function completedHandler()
{
// emojiParsedJson = JSON.parse(EmojiJSON.emoji_json) // emojiParsedJson = JSON.parse(EmojiJSON.emoji_json)
emojiParsedJson = EmojiJSON.emoji_json emojiParsedJson = EmojiJSON.emoji_json
for (var i = 0; i < emojiParsedJson.emoji_categories.length; i++) { for (var i = 0; i < emojiParsedJson.emoji_categories.length; i++)
{
var elem = emojiParsedJson.emoji_categories[i] var elem = emojiParsedJson.emoji_categories[i]
emojiCategoryButtons.append({eCatName: elem.name, eCatText: elem.emoji_unified}) emojiCategoryButtons.append({eCatName: elem.name, eCatText: elem.emoji_unified})
} }
@ -56,29 +66,39 @@ Rectangle {
//checks if the previous character is an Emoji and adds a ' ' if that's the case //checks if the previous character is an Emoji and adds a ' ' if that's the case
//this is necessary, because Emoji use a bigger font-size, and that font-size is kept using without a ' ' //this is necessary, because Emoji use a bigger font-size, and that font-size is kept using without a ' '
function keyPressedHandler(event) { function keyPressedHandler(event)
{
var testStr = textArea.getText(textArea.length-2, textArea.length) var testStr = textArea.getText(textArea.length-2, textArea.length)
var ptrn = new RegExp("[\uD800-\uDBFF][\uDC00-\uDFFF]") var ptrn = new RegExp("[\uD800-\uDBFF][\uDC00-\uDFFF]")
if ((event.key !== Qt.Key_Backspace) && (ptrn.test(testStr))) { if ((event.key !== Qt.Key_Backspace) && (ptrn.test(testStr)))
{
textArea.text += " " textArea.text += " "
textArea.cursorPosition = textArea.length textArea.cursorPosition = textArea.length
} }
} }
//all emoji of one category //all emoji of one category
ListModel { ListModel
{
id: emojiByCategory id: emojiByCategory
} }
GridView { GridView
{
id: emojiGrid id: emojiGrid
width: parent.width width: parent.width
anchors.fill: parent anchors.fill: parent
anchors.bottomMargin: buttonWidth anchors
{
bottomMargin: if (!androidMode) buttonWidth
topMargin: if (androidMode) buttonWidth
}
cellWidth: buttonWidth; cellHeight: buttonWidth cellWidth: buttonWidth; cellHeight: buttonWidth
model: emojiByCategory model: emojiByCategory
delegate: EmojiButton { delegate: EmojiButton
{
width: buttonWidth width: buttonWidth
height: buttonWidth height: buttonWidth
color: emojiPicker.color color: emojiPicker.color
@ -88,37 +108,52 @@ Rectangle {
//seperator //seperator
Rectangle { Rectangle
color: emojiPicker.color {
anchors.bottom: parent.bottom color: "gray"
width: parent.width anchors
height: buttonWidth {
bottom: if (!androidMode) parent.bottom
top: if (androidMode) parent.top
bottomMargin: if (!androidMode) buttonWidth
topMargin: if (androidMode) buttonWidth
} }
Rectangle {
color: "black"
anchors.bottom: parent.bottom
anchors.bottomMargin: buttonWidth
width: parent.width width: parent.width
height: 1 height: 1
} }
Rectangle
{
color: emojiPicker.color
width: parent.width
height: buttonWidth
anchors
{
bottom: if (!androidMode) parent.bottom
top: if (androidMode) parent.top
}
//emoji category selector //emoji category selector
ListView { ListView
{
width: parent.width width: parent.width
anchors.bottom: parent.bottom
anchors.bottomMargin: buttonWidth
orientation: ListView.Horizontal orientation: ListView.Horizontal
anchors.fill: parent
model: emojiCategoryButtons model: emojiCategoryButtons
delegate: EmojiCategoryButton { delegate: EmojiCategoryButton
{
width: buttonWidth width: buttonWidth
height: buttonWidth height: buttonWidth
color: emojiPicker.color color: emojiPicker.color
fontName: rootFontName fontName: rootFontName
} }
} }
}
ListModel { ListModel
{
id: emojiCategoryButtons id: emojiCategoryButtons
} }