mirror of
https://github.com/YACReader/yacreader
synced 2025-06-03 00:58:32 -04:00
Translator updated. Removed webkit dependency.
This commit is contained in:
parent
d98ad78251
commit
9ccc5a67eb
@ -29,7 +29,7 @@ INCLUDEPATH += /usr/local/include/poppler/qt4
|
||||
LIBS += -L/usr/local/lib -lpoppler-qt4
|
||||
}
|
||||
|
||||
QT += network webkit phonon opengl
|
||||
QT += network phonon opengl
|
||||
CONFIG += release
|
||||
CONFIG -= flat
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
<file>../files/about.html</file>
|
||||
<file>../files/helpYACReader.html</file>
|
||||
<file>../files/shortcuts.html</file>
|
||||
<file>../files/translator.html</file>
|
||||
</qresource>
|
||||
|
||||
<qresource lang="es_ES">
|
||||
|
@ -69,5 +69,9 @@
|
||||
<file>../images/useNewFlowButton.png</file>
|
||||
<file>../images/useOldFlowButton.png</file>
|
||||
<file>../images/notificationsLabel.png</file>
|
||||
<file>../images/fromTo.png</file>
|
||||
<file>../images/dropDownArrow.png</file>
|
||||
<file>../images/translatorSearch.png</file>
|
||||
<file>../images/speaker.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -6,63 +6,285 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include "translator.h"
|
||||
|
||||
#include "yacreader_busy_widget.h"
|
||||
|
||||
#include <QWebView>
|
||||
#include <QFile>
|
||||
#include <QPoint>
|
||||
#include <QWidget>
|
||||
#include <QTextCodec>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QComboBox>
|
||||
#include <QThread>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "translator.h"
|
||||
#include <QMessageBox>
|
||||
|
||||
#define APPID "417CEAD93449502CC3C9B69FED26C54118E62BCC"
|
||||
|
||||
YACReaderTranslator::YACReaderTranslator(QWidget * parent)
|
||||
:QWidget(parent)
|
||||
:QWidget(parent),drag(false)
|
||||
{
|
||||
QString scrollBarStyle = "QScrollBar:vertical { border: none; background: #404040; width: 7px; margin: 0 3px 0 0; }"
|
||||
"QScrollBar::handle:vertical { background: #DDDDDD; width: 7px; min-height: 20px; }"
|
||||
"QScrollBar::add-line:vertical { border: none; background: #404040; height: 10px; subcontrol-position: bottom; subcontrol-origin: margin; margin: 0 3px 0 0;}"
|
||||
|
||||
"QScrollBar::sub-line:vertical { border: none; background: #404040; height: 10px; subcontrol-position: top; subcontrol-origin: margin; margin: 0 3px 0 0;}"
|
||||
"QScrollBar::up-arrow:vertical {border:none;width: 9px;height: 6px;background: url(':/images/folders_view/line-up.png') center top no-repeat;}"
|
||||
"QScrollBar::down-arrow:vertical {border:none;width: 9px;height: 6px;background: url(':/images/folders_view/line-down.png') center top no-repeat;}"
|
||||
|
||||
"QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {background: none; }";
|
||||
|
||||
this->setCursor(QCursor(Qt::ArrowCursor));
|
||||
this->setAutoFillBackground(true);
|
||||
this->setBackgroundRole(QPalette::Window);
|
||||
QPalette p(this->palette());
|
||||
p.setColor(QPalette::Window, QColor(96,96,96));
|
||||
p.setColor(QPalette::Window, QColor("#404040"));
|
||||
this->setPalette(p);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
QWebView * view = new QWebView();
|
||||
QFile f(":/files/translator.html");
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream txtS(&f);
|
||||
txtS.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
QString contentHTML = txtS.readAll();
|
||||
view->setHtml(contentHTML);
|
||||
view->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
|
||||
connect(view->page(),SIGNAL(linkClicked(QUrl)),this,SLOT(play(QUrl)));
|
||||
|
||||
QHBoxLayout * buttonBar = new QHBoxLayout();
|
||||
//TITLE BAR
|
||||
QHBoxLayout * titleBar = new QHBoxLayout();
|
||||
QPushButton * close = new QPushButton(QIcon(QPixmap(":/images/close.png")),"");
|
||||
close->setFlat(true);
|
||||
buttonBar->addStretch();
|
||||
close->resize(18,18);
|
||||
buttonBar->addWidget(close);
|
||||
buttonBar->setMargin(0);
|
||||
QLabel * title = new QLabel(tr("YACReader translator"));
|
||||
title->setStyleSheet("QLabel {font-size:18px; font-family:Arial; color:white;}");
|
||||
titleBar->addWidget(title);
|
||||
titleBar->addStretch();
|
||||
close->resize(14,14);
|
||||
close->setStyleSheet("QPushButton {margin:0;padding:0;border:none;}");
|
||||
titleBar->addWidget(close);
|
||||
titleBar->setContentsMargins(0,0,0,0);
|
||||
titleBar->setSpacing(0);
|
||||
connect(close,SIGNAL(clicked()),this->parent(),SLOT(animateHideTranslator()));
|
||||
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(0);
|
||||
layout->addLayout(titleBar);
|
||||
|
||||
layout->addLayout(buttonBar);
|
||||
layout->addWidget(view);
|
||||
//INPUT TEXT
|
||||
text = new QTextEdit(this);
|
||||
text->setMinimumHeight(110);
|
||||
text->setMaximumHeight(110);
|
||||
layout->addSpacing(12);
|
||||
layout->addWidget(text);
|
||||
text->setStyleSheet("QTextEdit{border:none;background:#2a2a2a;color:white; font-size:12px; padding:6px;}"+scrollBarStyle);
|
||||
|
||||
resize(view->size().width()/1.60,view->size().height());
|
||||
//COMBOBOXES
|
||||
QHBoxLayout * combos = new QHBoxLayout();
|
||||
from = new QComboBox(this);
|
||||
to = new QComboBox(this);
|
||||
QString comboBoxStyle = "QComboBox {border:none;background:#2a2a2a;color:white;font-size:12px;font-family:Arial;padding-left:8px;}"
|
||||
"QComboBox::down-arrow {image: url(:/images/dropDownArrow.png);}"
|
||||
"QComboBox::drop-down {border:none; padding-right:10px;}"
|
||||
"QComboBox QAbstractItemView {border: none; background:#272727; color:white; selection-background-color: #202020; outline:none;}"
|
||||
"QComboBox QAbstractItemView::item {padding-left:8px;}" + scrollBarStyle
|
||||
;
|
||||
from->setStyleSheet(comboBoxStyle);
|
||||
to->setStyleSheet(comboBoxStyle);
|
||||
from->setFixedHeight(22);
|
||||
to->setFixedHeight(22);
|
||||
QLabel * arrow = new QLabel(this);
|
||||
QPixmap arrowPixmap(":/images/fromTo.png");
|
||||
arrow->setPixmap(arrowPixmap);
|
||||
QPushButton * searchButton = new QPushButton(this);
|
||||
searchButton->setIcon(QIcon(":/images/translatorSearch.png"));
|
||||
searchButton->setStyleSheet("QPushButton {border:none; background:#2a2a2a;}");
|
||||
searchButton->setFixedSize(22,22);
|
||||
combos->addWidget(from,1);
|
||||
combos->addSpacing(9);
|
||||
combos->addWidget(arrow,0);
|
||||
combos->addSpacing(9);
|
||||
combos->addWidget(to,1);
|
||||
combos->addSpacing(9);
|
||||
combos->addWidget(searchButton,0);
|
||||
layout->addSpacing(12);
|
||||
layout->addLayout(combos);
|
||||
|
||||
|
||||
//RESULTS
|
||||
QHBoxLayout * resultsTitleLayout = new QHBoxLayout();
|
||||
resultsTitle = new QLabel(tr("Translation"));
|
||||
resultsTitle->setStyleSheet("QLabel {font-family:Arial;font-size:14px;color:#e3e3e3;}");
|
||||
speakButton = new QPushButton(this);
|
||||
speakButton->setStyleSheet("QPushButton {border:none;}");
|
||||
speakButton->setIcon(QIcon(":/images/speaker.png"));
|
||||
resultsTitleLayout->addWidget(resultsTitle,0,Qt::AlignVCenter);
|
||||
resultsTitleLayout->addSpacing(10);
|
||||
resultsTitleLayout->addWidget(speakButton,0,Qt::AlignVCenter);
|
||||
resultsTitleLayout->addStretch();
|
||||
|
||||
layout->addSpacing(15);
|
||||
layout->addLayout(resultsTitleLayout);
|
||||
layout->addSpacing(12);
|
||||
|
||||
resultText = new QLabel();
|
||||
resultText->setWordWrap(true);
|
||||
resultText->setStyleSheet("QLabel {color:white;font-size:12px;}");
|
||||
resultText->setText("ñlkas lakj dflkaj lasd jflie lkajd fie kljads ijef lasei afsliej ljse f");
|
||||
layout->addWidget(resultText);
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
//CLEAR BUTTON
|
||||
clearButton = new QPushButton(tr("clear"));
|
||||
layout->addWidget(clearButton,0,Qt::AlignRight);
|
||||
clearButton->setMinimumWidth(95);
|
||||
clearButton->setStyleSheet("QPushButton {border:1px solid #212121; background:#2a2a2a; color:white; font-family:Arial; font-size:12px; padding-top:5px; padding-bottom:5px;}");
|
||||
|
||||
resize(400,479);
|
||||
|
||||
music = createPlayer(MusicCategory);
|
||||
|
||||
layout->setMargin(0);
|
||||
layout->setContentsMargins(18,12,18,12);
|
||||
setContentsMargins(0,0,0,0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
hideResults();
|
||||
populateCombos();
|
||||
|
||||
busyIndicator = new YACReaderBusyWidget(this);
|
||||
busyIndicator->move((this->width()-busyIndicator->width())/2,(this->height()-busyIndicator->height())*2/3);
|
||||
busyIndicator->hide();
|
||||
|
||||
show();
|
||||
|
||||
connect(searchButton,SIGNAL(pressed()),this,SLOT(translate()));
|
||||
connect(speakButton,SIGNAL(pressed()),this,SLOT(play()));
|
||||
connect(clearButton,SIGNAL(pressed()),this,SLOT(clear()));
|
||||
}
|
||||
|
||||
void YACReaderTranslator::play(const QUrl & url)
|
||||
void YACReaderTranslator::hideResults()
|
||||
{
|
||||
MediaSource src(url);
|
||||
resultsTitle->setHidden(true);
|
||||
speakButton->setHidden(true);
|
||||
resultText->setHidden(true);
|
||||
}
|
||||
|
||||
void YACReaderTranslator::clear()
|
||||
{
|
||||
hideResults();
|
||||
text->clear();
|
||||
}
|
||||
|
||||
void YACReaderTranslator::translate()
|
||||
{
|
||||
QString text = this->text->toPlainText();
|
||||
if(text.isEmpty())
|
||||
return;
|
||||
QString from = this->from->itemData(this->from->currentIndex()).toString();
|
||||
QString to = this->to->itemData(this->to->currentIndex()).toString();
|
||||
|
||||
TranslationLoader * translationLoader = new TranslationLoader(text,from,to);
|
||||
connect(translationLoader,SIGNAL(requestFinished(QString)),this,SLOT(setTranslation(QString)));
|
||||
connect(translationLoader,SIGNAL(error()),this,SLOT(error()));
|
||||
connect(translationLoader,SIGNAL(timeOut()),this,SLOT(error()));
|
||||
connect(translationLoader,SIGNAL(finished()),translationLoader,SLOT(deleteLater()));
|
||||
|
||||
TextToSpeachLoader * tts = new TextToSpeachLoader(text,from);
|
||||
connect(tts,SIGNAL(requestFinished(QUrl)),this,SLOT(setSpeak(QUrl)));
|
||||
connect(tts,SIGNAL(error()),this,SLOT(error()));
|
||||
connect(tts,SIGNAL(timeOut()),this,SLOT(error()));
|
||||
connect(tts,SIGNAL(finished()),tts,SLOT(deleteLater()));
|
||||
|
||||
translationLoader->start();
|
||||
tts->start();
|
||||
|
||||
resultsTitle->setText(tr("Translation"));
|
||||
|
||||
hideResults();
|
||||
|
||||
busyIndicator->show();
|
||||
}
|
||||
|
||||
void YACReaderTranslator::error()
|
||||
{
|
||||
resultsTitle->setText(tr("Service not available"));
|
||||
resultsTitle->setHidden(false);
|
||||
busyIndicator->hide();
|
||||
}
|
||||
|
||||
void YACReaderTranslator::setSpeak(const QUrl & url)
|
||||
{
|
||||
resultsTitle->setHidden(false);
|
||||
speakButton->setHidden(false);
|
||||
|
||||
ttsSource = url;
|
||||
}
|
||||
|
||||
void YACReaderTranslator::setTranslation(const QString & string)
|
||||
{
|
||||
resultText->setText(string);
|
||||
|
||||
resultsTitle->setHidden(false);
|
||||
resultText->setHidden(false);
|
||||
busyIndicator->hide();
|
||||
}
|
||||
|
||||
void YACReaderTranslator::populateCombos()
|
||||
{
|
||||
QList<QComboBox *> combos;
|
||||
combos.append(from);
|
||||
combos.append(to);
|
||||
|
||||
for(int i=0;i<combos.count();i++)
|
||||
{
|
||||
QComboBox * combo = combos.at(i);
|
||||
combo->addItem("Arabic","ar");
|
||||
combo->addItem("Bulgarian","bg");
|
||||
combo->addItem("Catalan","ca");
|
||||
combo->addItem("Chinese Simplified","zh-CHS");
|
||||
combo->addItem("Chinese Traditional","zh-CHT");
|
||||
combo->addItem("Czech","cs");
|
||||
combo->addItem("Danish","da");
|
||||
combo->addItem("Dutch","nl");
|
||||
combo->addItem("English","en");
|
||||
combo->addItem("Estonian","et");
|
||||
combo->addItem("Finnish","fi");
|
||||
combo->addItem("French","fr");
|
||||
combo->addItem("German","de");
|
||||
combo->addItem("Greek","el");
|
||||
combo->addItem("Haitian Creole","ht");
|
||||
combo->addItem("Hebrew","he");
|
||||
combo->addItem("Hindi","hi");
|
||||
combo->addItem("Hungarian","hu");
|
||||
combo->addItem("Indonesian","id");
|
||||
combo->addItem("Italian","it");
|
||||
combo->addItem("Japanese","ja");
|
||||
combo->addItem("Korean","ko");
|
||||
combo->addItem("Latvian","lv");
|
||||
combo->addItem("Lithuanian","lt");
|
||||
combo->addItem("Norwegian","no");
|
||||
combo->addItem("Polish","pl");
|
||||
combo->addItem("Portuguese","pt");
|
||||
combo->addItem("Romanian","ro");
|
||||
combo->addItem("Russian","ru");
|
||||
combo->addItem("Slovak","sk");
|
||||
combo->addItem("Slovenian","sl");
|
||||
combo->addItem("Spanish","es");
|
||||
combo->addItem("Swedish","sv");
|
||||
combo->addItem("Thai","th");
|
||||
combo->addItem("Turkish","tr");
|
||||
combo->addItem("Ukrainian","uk");
|
||||
combo->addItem("Vietnamese","vi");
|
||||
}
|
||||
from->setCurrentIndex(from->findText("English"));
|
||||
to->setCurrentIndex(from->findText("Spanish"));
|
||||
}
|
||||
|
||||
void YACReaderTranslator::play()
|
||||
{
|
||||
//QMessageBox::question(this,"xxx",ttsSource.toString());
|
||||
MediaSource src(ttsSource);
|
||||
src.setAutoDelete(true);
|
||||
music->setCurrentSource(src);
|
||||
music->play();
|
||||
music->setCurrentSource(src);
|
||||
music->play();
|
||||
}
|
||||
|
||||
YACReaderTranslator::~YACReaderTranslator()
|
||||
@ -72,8 +294,12 @@ YACReaderTranslator::~YACReaderTranslator()
|
||||
|
||||
void YACReaderTranslator::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
drag = true;
|
||||
click = event->pos();
|
||||
QPoint p = mapTo(this,event->pos());
|
||||
if(p.y() < 40)
|
||||
{
|
||||
drag = true;
|
||||
click = event->pos();
|
||||
}
|
||||
}
|
||||
|
||||
void YACReaderTranslator::mouseReleaseEvent(QMouseEvent *event)
|
||||
@ -88,3 +314,94 @@ void YACReaderTranslator::mouseMoveEvent(QMouseEvent * event)
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TranslationLoader::TranslationLoader(QString text, QString from, QString to)
|
||||
:QThread(),text(text),from(from),to(to)
|
||||
{
|
||||
}
|
||||
|
||||
void TranslationLoader::run()
|
||||
{
|
||||
QNetworkAccessManager manager;
|
||||
QEventLoop q;
|
||||
QTimer tT;
|
||||
|
||||
tT.setSingleShot(true);
|
||||
connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
|
||||
connect(&manager, SIGNAL(finished(QNetworkReply*)),&q, SLOT(quit()));
|
||||
|
||||
QString url = "http://api.microsofttranslator.com/V2/Ajax.svc/Translate?appid=%1&from=%2&to=%3&text=%4&contentType=text/plain";
|
||||
url = url.arg(APPID).arg(from).arg(to).arg(text);
|
||||
|
||||
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl(url)));
|
||||
|
||||
tT.start(5000); // 5s timeout
|
||||
q.exec();
|
||||
|
||||
if(tT.isActive()){
|
||||
// download complete
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
QString utf8 = QString::fromUtf8(reply->readAll());
|
||||
utf8 = utf8.remove(0,1);
|
||||
utf8 = utf8.remove(utf8.count()-1,1);
|
||||
|
||||
QString translated(utf8);
|
||||
emit(requestFinished(translated));
|
||||
}
|
||||
else
|
||||
emit(error());
|
||||
} else {
|
||||
emit(timeOut());
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
TextToSpeachLoader::TextToSpeachLoader(QString text, QString language)
|
||||
:QThread(),text(text),language(language)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void TextToSpeachLoader::run()
|
||||
{
|
||||
QNetworkAccessManager manager;
|
||||
QEventLoop q;
|
||||
QTimer tT;
|
||||
|
||||
tT.setSingleShot(true);
|
||||
connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
|
||||
connect(&manager, SIGNAL(finished(QNetworkReply*)),&q, SLOT(quit()));
|
||||
|
||||
QString url = "http://api.microsofttranslator.com/V2/Ajax.svc/Speak?appid=%1&language=%2&text=%3&contentType=text/plain";
|
||||
url = url.arg(APPID).arg(language).arg(text);
|
||||
|
||||
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl(url)));
|
||||
|
||||
tT.start(5000); // 5s timeout
|
||||
q.exec();
|
||||
|
||||
if(tT.isActive()){
|
||||
// download complete
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
QString utf8 = QString::fromUtf8(reply->readAll());
|
||||
utf8 = utf8.remove(0,1);
|
||||
utf8 = utf8.remove(utf8.count()-1,1);
|
||||
utf8 = utf8.replace("\\","");
|
||||
|
||||
emit(requestFinished(QUrl(utf8)));
|
||||
}
|
||||
else
|
||||
emit(error());
|
||||
} else {
|
||||
emit(timeOut());
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,16 @@
|
||||
class QUrl;
|
||||
class QMouseEvent;
|
||||
class QPoint;
|
||||
#include<QWidget>
|
||||
class QTextEdit;
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class YACReaderBusyWidget;
|
||||
|
||||
#include <QWidget>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
|
||||
#include<Phonon/MediaObject>
|
||||
|
||||
using namespace Phonon;
|
||||
@ -17,16 +26,66 @@ class YACReaderTranslator : public QWidget
|
||||
~YACReaderTranslator();
|
||||
|
||||
public slots:
|
||||
void play(const QUrl & url);
|
||||
void play();
|
||||
|
||||
protected slots:
|
||||
void translate();
|
||||
void setSpeak(const QUrl & url);
|
||||
void setTranslation(const QString & string);
|
||||
void error();
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent ( QMouseEvent * event );
|
||||
void hideResults();
|
||||
|
||||
void populateCombos();
|
||||
bool drag;
|
||||
QPoint click;
|
||||
private:
|
||||
MediaObject * music;
|
||||
QTextEdit * text;
|
||||
QComboBox * from;
|
||||
QComboBox * to;
|
||||
QLabel * resultsTitle;
|
||||
QPushButton * speakButton;
|
||||
QLabel * resultText;
|
||||
YACReaderBusyWidget * busyIndicator;
|
||||
QUrl ttsSource;
|
||||
QPushButton * clearButton;
|
||||
|
||||
};
|
||||
|
||||
class TranslationLoader : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TranslationLoader(QString text, QString from, QString to);
|
||||
signals:
|
||||
void requestFinished(QString);
|
||||
void timeOut();
|
||||
void error();
|
||||
private:
|
||||
QString text;
|
||||
QString from;
|
||||
QString to;
|
||||
void run();
|
||||
};
|
||||
|
||||
class TextToSpeachLoader : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TextToSpeachLoader(QString text, QString language);
|
||||
signals:
|
||||
void requestFinished(QUrl);
|
||||
void timeOut();
|
||||
void error();
|
||||
private:
|
||||
QString text;
|
||||
QString language;
|
||||
void run();
|
||||
};
|
||||
#endif
|
@ -12,7 +12,6 @@
|
||||
#include "page_label_widget.h"
|
||||
#include "notifications_label_widget.h"
|
||||
|
||||
#include <QWebView>
|
||||
#include <QFile>
|
||||
#define STEPS 22
|
||||
|
||||
|
BIN
images/close.png
BIN
images/close.png
Binary file not shown.
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 215 B |
BIN
images/dropDownArrow.png
Normal file
BIN
images/dropDownArrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 B |
BIN
images/fromTo.png
Normal file
BIN
images/fromTo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 171 B |
BIN
images/speaker.png
Normal file
BIN
images/speaker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 200 B |
BIN
images/translatorSearch.png
Normal file
BIN
images/translatorSearch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 241 B |
Loading…
x
Reference in New Issue
Block a user