diff --git a/README.md b/README.md
index 26bd66749..2c55936ed 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,6 @@ This client runs on Windows, Linux and Mac natively.
##Developer overview:
-[GitStats](http://207.12.89.155/index.html)
+[GitStats](http://104.219.184.93/index.html)
[Mac & Linux jenkins](https://jenkins.libtoxcore.so/user/tux3/my-views/view/qTox/)
-[Windows jenkins](http://207.12.89.155:8080)
+[Windows jenkins](http://104.219.184.93:8080)
diff --git a/qtox.pro b/qtox.pro
index 7ad00b4b3..d8c76f360 100644
--- a/qtox.pro
+++ b/qtox.pro
@@ -78,6 +78,14 @@ win32 {
LIBS += -liphlpapi -L$$PWD/libs/lib -lsodium -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
LIBS += -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32 -lz
+
+ contains(DEFINES, QTOX_FILTER_AUDIO) {
+ contains(STATICPKG, YES) {
+ LIBS += -Wl,-Bstatic -lfilteraudio
+ } else {
+ LIBS += -lfilteraudio
+ }
+ }
} else {
macx {
BUNDLEID = im.tox.qtox
diff --git a/res.qrc b/res.qrc
index 0b461bf8e..d4a844ede 100644
--- a/res.qrc
+++ b/res.qrc
@@ -127,6 +127,7 @@
translations/mannol.qmtranslations/pirate.qmtranslations/pl.qm
+ translations/pt.qmtranslations/ru.qmtranslations/sv.qmtranslations/uk.qm
diff --git a/src/audio.cpp b/src/audio.cpp
index d90d5d48e..64e0b0961 100644
--- a/src/audio.cpp
+++ b/src/audio.cpp
@@ -15,22 +15,40 @@
*/
+// Output some extra debug info
+#define AUDIO_DEBUG 1
+
+// Fix a 7 years old openal-soft/alsa bug
+// http://blog.gmane.org/gmane.comp.lib.openal.devel/month=20080501
+// If set to 1, the capture will be started as long as the device is open
+#define FIX_SND_PCM_PREPARE_BUG 0
+
#include "audio.h"
#include "src/core.h"
#include
#include
+#include
#include
std::atomic Audio::userCount{0};
Audio* Audio::instance{nullptr};
QThread* Audio::audioThread{nullptr};
+QMutex* Audio::audioInLock{nullptr};
+QMutex* Audio::audioOutLock{nullptr};
ALCdevice* Audio::alInDev{nullptr};
ALCdevice* Audio::alOutDev{nullptr};
ALCcontext* Audio::alContext{nullptr};
ALuint Audio::alMainSource{0};
+void audioDebugLog(QString msg)
+{
+#if (AUDIO_DEBUG)
+ qDebug()<<"Audio: "<setObjectName("qTox Audio");
audioThread->start();
+ audioInLock = new QMutex(QMutex::Recursive);
+ audioOutLock = new QMutex(QMutex::Recursive);
instance->moveToThread(audioThread);
}
return *instance;
@@ -46,18 +66,46 @@ Audio& Audio::getInstance()
void Audio::suscribeInput()
{
+ if (!alInDev)
+ {
+ qWarning()<<"Audio::suscribeInput: input device is closed";
+ return;
+ }
+
+ audioDebugLog("suscribing");
+ QMutexLocker lock(audioInLock);
if (!userCount++ && alInDev)
+ {
+#if (!FIX_SND_PCM_PREPARE_BUG)
+ audioDebugLog("starting capture");
alcCaptureStart(alInDev);
+#endif
+ }
}
void Audio::unsuscribeInput()
{
+ if (!alInDev)
+ {
+ qWarning()<<"Audio::unsuscribeInput: input device is closed";
+ return;
+ }
+
+ audioDebugLog("unsuscribing");
+ QMutexLocker lock(audioInLock);
if (!--userCount && alInDev)
+ {
+#if (!FIX_SND_PCM_PREPARE_BUG)
+ audioDebugLog("stopping capture");
alcCaptureStop(alInDev);
+#endif
+ }
}
void Audio::openInput(const QString& inDevDescr)
{
+ audioDebugLog("Trying to open input "+inDevDescr);
+ QMutexLocker lock(audioInLock);
auto* tmp = alInDev;
alInDev = nullptr;
if (tmp)
@@ -80,11 +128,22 @@ void Audio::openInput(const QString& inDevDescr)
// Restart the capture if necessary
if (userCount.load() != 0 && alInDev)
+ {
alcCaptureStart(alInDev);
+ }
+ else
+ {
+#if (FIX_SND_PCM_PREPARE_BUG)
+ alcCaptureStart(alInDev);
+#endif
+ }
+
}
void Audio::openOutput(const QString& outDevDescr)
{
+ audioDebugLog("Trying to open output "+outDevDescr);
+ QMutexLocker lock(audioOutLock);
auto* tmp = alOutDev;
alOutDev = nullptr;
if (outDevDescr.isEmpty())
@@ -97,11 +156,8 @@ void Audio::openOutput(const QString& outDevDescr)
}
else
{
- if (alContext)
- {
- alcMakeContextCurrent(nullptr);
+ if (alContext && alcMakeContextCurrent(nullptr) == ALC_TRUE)
alcDestroyContext(alContext);
- }
if (tmp)
alcCloseDevice(tmp);
alContext=alcCreateContext(alOutDev,nullptr);
@@ -122,26 +178,48 @@ void Audio::openOutput(const QString& outDevDescr)
void Audio::closeInput()
{
+ audioDebugLog("Closing input");
+ QMutexLocker lock(audioInLock);
if (alInDev)
- alcCaptureCloseDevice(alInDev);
-
- userCount = 0;
+ {
+ if (alcCaptureCloseDevice(alInDev) == ALC_TRUE)
+ {
+ alInDev = nullptr;
+ userCount = 0;
+ }
+ else
+ {
+ qWarning() << "Audio: Failed to close input";
+ }
+ }
}
void Audio::closeOutput()
{
- if (alContext)
- {
- alcMakeContextCurrent(nullptr);
+ audioDebugLog("Closing output");
+ QMutexLocker lock(audioOutLock);
+ if (alContext && alcMakeContextCurrent(nullptr) == ALC_TRUE)
alcDestroyContext(alContext);
- }
if (alOutDev)
- alcCloseDevice(alOutDev);
+ {
+ if (alcCloseDevice(alOutDev) == ALC_TRUE)
+ {
+ alOutDev = nullptr;
+ }
+ else
+ {
+ qWarning() << "Audio: Failed to close output";
+ }
+ }
}
void Audio::playMono16Sound(const QByteArray& data)
{
+ QMutexLocker lock(audioOutLock);
+ if (!alOutDev)
+ return;
+
ALuint buffer;
alGenBuffers(1, &buffer);
alBufferData(buffer, AL_FORMAT_MONO16, data.data(), data.size(), 44100);
@@ -163,6 +241,8 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data,
{
assert(QThread::currentThread() == audioThread);
+ QMutexLocker lock(audioOutLock);
+
ToxGroupCall& call = Core::groupCalls[group];
if (!call.active || call.muteVol)
@@ -178,6 +258,8 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
{
assert(channels == 1 || channels == 2);
+ QMutexLocker lock(audioOutLock);
+
ALuint bufid;
ALint processed = 0, queued = 16;
alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);
@@ -210,3 +292,27 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
if (state != AL_PLAYING)
alSourcePlay(alSource);
}
+
+bool Audio::isInputReady()
+{
+ return (alInDev && userCount);
+}
+
+bool Audio::isOutputClosed()
+{
+ return (alOutDev);
+}
+
+bool Audio::tryCaptureSamples(uint8_t* buf, int framesize)
+{
+ QMutexLocker lock(audioInLock);
+
+ ALint samples=0;
+ alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
+ if (samples < framesize)
+ return false;
+
+ memset(buf, 0, framesize * 2 * av_DefaultSettings.audio_channels); // Avoid uninitialized values (Valgrind)
+ alcCaptureSamples(Audio::alInDev, buf, framesize);
+ return true;
+}
diff --git a/src/audio.h b/src/audio.h
index 9c4f87353..6fb8e7107 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -34,6 +34,7 @@ class QString;
class QByteArray;
class QTimer;
class QThread;
+class QMutex;
struct Tox;
class Audio : QObject
@@ -52,7 +53,11 @@ public:
static void closeInput(); ///< Close an input device, please don't use unless everyone's unsuscribed
static void closeOutput(); ///< Close an output device
+ static bool isInputReady(); ///< Returns true if the input device is open and suscribed to
+ static bool isOutputClosed(); ///< Returns true if the output device is open
+
static void playMono16Sound(const QByteArray& data); ///< Play a 44100Hz mono 16bit PCM sound
+ static bool tryCaptureSamples(uint8_t* buf, int framesize); ///< Does nothing and return false on failure
/// May be called from any thread, will always queue a call to playGroupAudio
/// The first and last argument are ignored, but allow direct compatibility with toxcore
@@ -66,7 +71,6 @@ public slots:
public:
static QThread* audioThread;
- static ALCdevice* alOutDev, *alInDev;
static ALCcontext* alContext;
static ALuint alMainSource;
@@ -77,6 +81,8 @@ private:
private:
static Audio* instance;
static std::atomic userCount;
+ static ALCdevice* alOutDev, *alInDev;
+ static QMutex* audioInLock, *audioOutLock;
};
#endif // AUDIO_H
diff --git a/src/autoupdate.cpp b/src/autoupdate.cpp
index 8c2a2ef02..4d6dbb87e 100644
--- a/src/autoupdate.cpp
+++ b/src/autoupdate.cpp
@@ -64,6 +64,7 @@ unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES];
const QString AutoUpdater::checkURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/version";
const QString AutoUpdater::flistURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/flist";
const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/files/";
+bool AutoUpdater::abortFlag{false};
bool AutoUpdater::isUpdateAvailable()
{
@@ -251,7 +252,11 @@ AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta)
QNetworkAccessManager *manager = new QNetworkAccessManager;
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(filesURI+fileMeta.id)));
while (!reply->isFinished())
+ {
+ if (abortFlag)
+ return file;
qApp->processEvents();
+ }
if (reply->error() != QNetworkReply::NoError)
{
@@ -280,6 +285,9 @@ bool AutoUpdater::downloadUpdate()
QList newFlist = parseFlist(newFlistData);
QList diff = genUpdateDiff(newFlist);
+ if (abortFlag)
+ return false;
+
qDebug() << "AutoUpdater: Need to update "< updateFlist = parseFlist(updateFlistData);
QList diff = genUpdateDiff(updateFlist);
+ // If the update wasn't downloaded correctly, redownload it
+ // We don't check signatures to not block qTox too long, the updater will do it anyway
for (UpdateFileMeta fileMeta : diff)
+ {
if (!QFile::exists(updateDirStr+fileMeta.installpath))
+ {
+ QtConcurrent::run(&AutoUpdater::downloadUpdate);
return false;
+ }
+
+ QFile f(updateDirStr+fileMeta.installpath);
+ if (f.size() != (int64_t)fileMeta.size)
+ {
+ QtConcurrent::run(&AutoUpdater::downloadUpdate);
+ return false;
+ }
+ }
return true;
}
@@ -433,3 +460,8 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
downloadUpdate();
}
}
+
+void AutoUpdater::abortUpdates()
+{
+ abortFlag = true;
+}
diff --git a/src/autoupdate.h b/src/autoupdate.h
index 4462db105..3937e3b20 100644
--- a/src/autoupdate.h
+++ b/src/autoupdate.h
@@ -78,15 +78,18 @@ public:
/// Will try to download an update, if successful returns true and qTox will apply it after a restart
/// Will try to follow qTox's proxy settings, may block and processEvents
static bool downloadUpdate();
- /// Returns true if an update is downloaded and ready to be installed
- /// If so, call installLocalUpdate. If not, call downloadUpdate.
- /// This only checks that we downloaded an update and didn't stop in the middle, not that every file is still valid
+ /// Returns true if an update is downloaded and ready to be installed,
+ /// if so, call installLocalUpdate.
+ /// If an update was partially downloaded, the function will resume asynchronously and return false
static bool isLocalUpdateReady();
/// Launches the qTox updater to try to install the local update and exits immediately
/// Will not check that the update actually exists, use isLocalUpdateReady first for that
/// The qTox updater will restart us after the update is done
/// Note: If we fail to start the qTox updater, we will delete the update and exit
[[ noreturn ]] static void installLocalUpdate();
+ /// Aborting will make some functions try to return early
+ /// Call before qTox exits to avoid the updater running in the background
+ static void abortUpdates();
protected:
/// Parses and validates a flist file. Returns an empty list on error
@@ -118,6 +121,7 @@ private:
static const QString filesURI; ///< URI of the actual files of the latest version
static const QString updaterBin; ///< Path to the qtox-updater binary
static unsigned char key[];
+ static bool abortFlag; ///< If true, try to abort everything.
};
#endif // AUTOUPDATE_H
diff --git a/src/coreav.cpp b/src/coreav.cpp
index 5fb12e128..b26be579c 100644
--- a/src/coreav.cpp
+++ b/src/coreav.cpp
@@ -214,6 +214,7 @@ void Core::cleanupCall(int callId)
if (calls[callId].videoEnabled)
Camera::getInstance()->unsubscribe();
Audio::unsuscribeInput();
+ toxav_kill_transmission(Core::getInstance()->toxav, callId);
}
void Core::playCallAudio(void* toxav, int32_t callId, const int16_t *data, uint16_t samples, void *user_data)
@@ -236,7 +237,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
if (!calls[callId].active)
return;
- if (calls[callId].muteMic || !Audio::alInDev)
+ if (calls[callId].muteMic || !Audio::isInputReady())
{
calls[callId].sendAudioTimer->start();
return;
@@ -246,17 +247,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels;
uint8_t buf[bufsize], dest[bufsize];
- bool frame = false;
- ALint samples;
- alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
- if (samples >= framesize)
- {
- memset(buf, 0, bufsize); // Avoid uninitialized values (Valgrind)
- alcCaptureSamples(Audio::alInDev, buf, framesize);
- frame = 1;
- }
-
- if (frame)
+ if (Audio::tryCaptureSamples(buf, framesize))
{
int r;
if ((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0)
@@ -268,10 +259,9 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
#ifdef QTOX_FILTER_AUDIO
if (filterer[callId])
- {
filterer[callId]->filterAudio((int16_t*) buf, framesize);
- }
#endif
+
if ((r = toxav_send_audio(toxav, callId, dest, r)) < 0)
{
qDebug() << "Core: toxav_send_audio error";
@@ -418,59 +408,6 @@ void Core::onAvRinging(void* _toxav, int32_t call_index, void* core)
}
}
-//void Core::onAvStarting(void* _toxav, int32_t call_index, void* core)
-//{
-// ToxAv* toxav = static_cast(_toxav);
-
-// int friendId = toxav_get_peer_id(toxav, call_index, 0);
-// if (friendId < 0)
-// {
-// qWarning() << "Core: Received invalid AV starting";
-// return;
-// }
-
-// ToxAvCSettings* transSettings = new ToxAvCSettings;
-// int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
-// if (err != ErrorNone)
-// {
-// qWarning() << "Core::onAvStarting: error getting call type";
-// delete transSettings;
-// return;
-// }
-
-// if (transSettings->call_type == TypeVideo)
-// {
-// qDebug() << QString("Core: AV starting from %1 with video").arg(friendId);
-// prepareCall(friendId, call_index, toxav, true);
-// emit static_cast(core)->avStarting(friendId, call_index, true);
-// }
-// else
-// {
-// qDebug() << QString("Core: AV starting from %1 without video").arg(friendId);
-// prepareCall(friendId, call_index, toxav, false);
-// emit static_cast(core)->avStarting(friendId, call_index, false);
-// }
-
-// delete transSettings;
-//}
-
-//void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
-//{
-// ToxAv* toxav = static_cast(_toxav);
-
-// int friendId = toxav_get_peer_id(toxav, call_index, 0);
-// if (friendId < 0)
-// {
-// qWarning() << "Core: Received invalid AV ending";
-// return;
-// }
-// qDebug() << QString("Core: AV ending from %1").arg(friendId);
-
-// cleanupCall(call_index);
-
-// emit static_cast(core)->avEnding(friendId, call_index);
-//}
-
void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
{
ToxAv* toxav = static_cast(_toxav);
@@ -669,7 +606,7 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
if (!groupCalls[groupId].active)
return;
- if (groupCalls[groupId].muteMic || !Audio::alInDev)
+ if (groupCalls[groupId].muteMic || !Audio::isInputReady())
{
groupCalls[groupId].sendAudioTimer->start();
return;
@@ -679,17 +616,7 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels;
uint8_t buf[bufsize];
- bool frame = false;
- ALint samples;
- alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
- if (samples >= framesize)
- {
- memset(buf, 0, bufsize); // Avoid uninitialized values (Valgrind)
- alcCaptureSamples(Audio::alInDev, buf, framesize);
- frame = 1;
- }
-
- if (frame)
+ if (Audio::tryCaptureSamples(buf, framesize))
{
int r;
if ((r = toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
diff --git a/src/group.cpp b/src/group.cpp
index 6a5ff4d8f..a75d933a2 100644
--- a/src/group.cpp
+++ b/src/group.cpp
@@ -145,7 +145,9 @@ GroupWidget *Group::getGroupWidget()
QStringList Group::getPeerList() const
{
- return peers.values();
+ QStringList peerNames(peers.values());
+ peerNames.sort(Qt::CaseInsensitive);
+ return peerNames;
}
void Group::setEventFlag(int f)
diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp
index 1f0e8a0c8..4efacb541 100644
--- a/src/misc/settings.cpp
+++ b/src/misc/settings.cpp
@@ -189,7 +189,7 @@ void Settings::load()
s.endGroup();
s.beginGroup("Privacy");
- typingNotification = s.value("typingNotification", false).toBool();
+ typingNotification = s.value("typingNotification", true).toBool();
enableLogging = s.value("enableLogging", false).toBool();
encryptLogs = s.value("encryptLogs", false).toBool();
encryptTox = s.value("encryptTox", false).toBool();
diff --git a/src/toxdns.cpp b/src/toxdns.cpp
index 1a5e3b0c5..5afdc73a0 100644
--- a/src/toxdns.cpp
+++ b/src/toxdns.cpp
@@ -219,6 +219,11 @@ fallbackOnTox1:
tox_dns3_kill(tox_dns3);
#if TOX1_SILENT_FALLBACK
toxIdStr = queryTox1(record, silent);
+#elif TOX1_ASK_FALLBACK
+ QMessageBox::StandardButton btn = QMessageBox::warning(nullptr, "qTox", tr("It appears that qTox has to use the old tox1 protocol.\n\
+Unfortunately tox1 is not secure. Should it be used anyway?"), QMessageBox::Ok|QMessageBox::No, QMessageBox::No);
+ if (btn == QMessageBox::Ok)
+ queryTox1(record, silent);
#endif
return toxIdStr;
}
@@ -258,6 +263,11 @@ ToxID ToxDNS::resolveToxAddress(const QString &address, bool silent)
{
#if TOX1_SILENT_FALLBACK
toxId = ToxID::fromString(queryTox1(address, silent));
+#elif TOX1_ASK_FALLBACK
+ QMessageBox::StandardButton btn = QMessageBox::warning(nullptr, "qTox", tr("It appears that qTox has to use the old tox1 protocol.\n\
+Unfortunately tox1 is not secure. Should it be used anyway?"), QMessageBox::Ok|QMessageBox::No, QMessageBox::No);
+ if (btn == QMessageBox::Ok)
+ toxId = ToxID::fromString(queryTox1(address, silent));
#else
return toxId;
#endif
diff --git a/src/toxdns.h b/src/toxdns.h
index a7a644041..91b907d5a 100644
--- a/src/toxdns.h
+++ b/src/toxdns.h
@@ -25,6 +25,9 @@
/// Tox1 is not encrypted, it's unsafe
#define TOX1_SILENT_FALLBACK 0
+/// That said if the user insists ...
+#define TOX1_ASK_FALLBACK 1
+
/// Handles tox1 and tox3 DNS queries
class ToxDNS : public QObject
{
diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp
index a0440e976..0874e696e 100644
--- a/src/widget/form/chatform.cpp
+++ b/src/widget/form/chatform.cpp
@@ -55,6 +55,15 @@ ChatForm::ChatForm(Friend* chatFriend)
statusMessageLabel->setFont(Style::getFont(Style::Medium));
statusMessageLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
+ isTypingLabel = new QLabel();
+ QFont font = isTypingLabel->font();
+ font.setItalic(true);
+ font.setPixelSize(8);
+ isTypingLabel->setFont(font);
+
+ QVBoxLayout* mainLayout = dynamic_cast(layout());
+ mainLayout->insertWidget(1, isTypingLabel);
+
netcam = new NetCamView();
timer = nullptr;
@@ -72,6 +81,7 @@ ChatForm::ChatForm(Friend* chatFriend)
connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered);
connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered);
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
+ connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged);
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
@@ -133,6 +143,21 @@ void ChatForm::onSendTriggered()
msgEdit->clear();
}
+void ChatForm::onTextEditChanged()
+{
+ bool isNowTyping;
+ if (!Settings::getInstance().isTypingNotificationEnabled())
+ isNowTyping = false;
+ else
+ isNowTyping = msgEdit->toPlainText().length() > 0;
+
+ if (isTyping != isNowTyping)
+ {
+ isTyping = isNowTyping;
+ Core::getInstance()->sendTyping(f->getFriendID(), isTyping);
+ }
+}
+
void ChatForm::onAttachClicked()
{
QStringList paths = QFileDialog::getOpenFileNames(0,tr("Send a file"));
@@ -211,10 +236,11 @@ void ChatForm::onFileRecvRequest(ToxFile file)
void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
{
- qDebug() << "onAvInvite";
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvInvite";
+
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@@ -248,10 +274,11 @@ void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
void ChatForm::onAvStart(int FriendId, int CallId, bool video)
{
- qDebug() << "onAvStart";
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvStart";
+
audioInputFlag = true;
audioOutputFlag = true;
callId = CallId;
@@ -282,11 +309,12 @@ void ChatForm::onAvStart(int FriendId, int CallId, bool video)
void ChatForm::onAvCancel(int FriendId, int)
{
- qDebug() << "onAvCancel";
-
+
if (FriendId != f->getFriendID())
return;
-
+
+ qDebug() << "onAvCancel";
+
stopCounter();
audioInputFlag = false;
@@ -311,11 +339,11 @@ void ChatForm::onAvCancel(int FriendId, int)
void ChatForm::onAvEnd(int FriendId, int)
{
- qDebug() << "onAvEnd";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvEnd";
+
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@@ -338,10 +366,11 @@ void ChatForm::onAvEnd(int FriendId, int)
void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
{
- qDebug() << "onAvRinging";
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvRinging";
+
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@@ -367,11 +396,11 @@ void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
void ChatForm::onAvStarting(int FriendId, int CallId, bool video)
{
- qDebug() << "onAvStarting";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvStarting";
+
callButton->disconnect();
videoButton->disconnect();
if (video)
@@ -398,11 +427,11 @@ void ChatForm::onAvStarting(int FriendId, int CallId, bool video)
void ChatForm::onAvEnding(int FriendId, int)
{
- qDebug() << "onAvEnding";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvEnding";
+
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@@ -427,11 +456,11 @@ void ChatForm::onAvEnding(int FriendId, int)
void ChatForm::onAvRequestTimeout(int FriendId, int)
{
- qDebug() << "onAvRequestTimeout";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvRequestTimeout";
+
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@@ -454,11 +483,11 @@ void ChatForm::onAvRequestTimeout(int FriendId, int)
void ChatForm::onAvPeerTimeout(int FriendId, int)
{
- qDebug() << "onAvPeerTimeout";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvPeerTimeout";
+
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@@ -481,11 +510,11 @@ void ChatForm::onAvPeerTimeout(int FriendId, int)
void ChatForm::onAvRejected(int FriendId, int)
{
- qDebug() << "onAvRejected";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvRejected";
+
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@@ -510,11 +539,11 @@ void ChatForm::onAvRejected(int FriendId, int)
void ChatForm::onAvMediaChange(int FriendId, int CallId, bool video)
{
- qDebug() << "onAvMediaChange";
-
if (FriendId != f->getFriendID() || CallId != callId)
return;
+ qDebug() << "onAvMediaChange";
+
if (video)
{
netcam->show(Core::getInstance()->getVideoSourceFromCall(CallId), f->getDisplayedName());
@@ -535,7 +564,7 @@ void ChatForm::onAnswerCallTriggered()
}
void ChatForm::onHangupCallTriggered()
-{
+{
qDebug() << "onHangupCallTriggered";
audioInputFlag = false;
@@ -571,11 +600,11 @@ void ChatForm::onVideoCallTriggered()
void ChatForm::onAvCallFailed(int FriendId)
{
- qDebug() << "onAvCallFailed";
-
if (FriendId != f->getFriendID())
return;
+ qDebug() << "onAvCallFailed";
+
audioInputFlag = false;
audioOutputFlag = false;
callButton->disconnect();
@@ -852,6 +881,14 @@ void ChatForm::dischargeReceipt(int receipt)
}
}
+void ChatForm::setFriendTyping(bool isTyping)
+{
+ if (isTyping)
+ isTypingLabel->setText(f->getDisplayedName() + " " + tr("is typing..."));
+ else
+ isTypingLabel->clear();
+}
+
void ChatForm::clearReciepts()
{
receipts.clear();
diff --git a/src/widget/form/chatform.h b/src/widget/form/chatform.h
index e22ad213a..031de32b7 100644
--- a/src/widget/form/chatform.h
+++ b/src/widget/form/chatform.h
@@ -39,6 +39,7 @@ public:
void loadHistory(QDateTime since, bool processUndelivered = false);
void dischargeReceipt(int receipt);
+ void setFriendTyping(bool isTyping);
signals:
void sendFile(int32_t friendId, QString, QString, long long);
@@ -75,6 +76,7 @@ public slots:
private slots:
void onSendTriggered();
+ void onTextEditChanged();
void onAttachClicked();
void onCallTriggered();
void onVideoCallTriggered();
@@ -99,6 +101,7 @@ private:
QLabel *callDuration;
QTimer *timer;
QElapsedTimer timeElapsed;
+ QLabel *isTypingLabel;
QHash ftransWidgets;
void startCounter();
@@ -106,6 +109,7 @@ private:
QString secondsToDHMS(quint32 duration);
QHash receipts;
QMap undeliveredMsgs;
+ bool isTyping;
};
#endif // CHATFORM_H
diff --git a/src/widget/form/loadhistorydialog.cpp b/src/widget/form/loadhistorydialog.cpp
index 3d7e36535..33c33bcc5 100644
--- a/src/widget/form/loadhistorydialog.cpp
+++ b/src/widget/form/loadhistorydialog.cpp
@@ -32,5 +32,11 @@ LoadHistoryDialog::~LoadHistoryDialog()
QDateTime LoadHistoryDialog::getFromDate()
{
QDateTime res(ui->fromDate->selectedDate());
+ if (res.date().month() != ui->fromDate->monthShown() || res.date().year() != ui->fromDate->yearShown())
+ {
+ QDate newDate(ui->fromDate->yearShown(), ui->fromDate->monthShown(), 1);
+ res.setDate(newDate);
+ }
+
return res;
}
diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp
index d3d80de9b..732e00a00 100644
--- a/src/widget/form/settings/generalform.cpp
+++ b/src/widget/form/settings/generalform.cpp
@@ -30,8 +30,8 @@
#include "src/autoupdate.h"
-static QStringList locales = {"bg", "de", "en", "es", "fr", "it", "mannol", "pirate", "pl", "ru", "fi", "sv", "uk"};
-static QStringList langs = {"Български", "Deutsch", "English", "Español", "Français", "Italiano", "mannol", "Pirate", "Polski", "Русский", "Suomi", "Svenska", "Українська"};
+static QStringList locales = {"bg", "de", "en", "es", "fr", "it", "mannol", "pirate", "pl", "pt", "ru", "fi", "sv", "uk"};
+static QStringList langs = {"Български", "Deutsch", "English", "Español", "Français", "Italiano", "mannol", "Pirate", "Polski", "Português", "Русский", "Suomi", "Svenska", "Українська"};
static QStringList timeFormats = {"hh:mm AP", "hh:mm", "hh:mm:ss AP", "hh:mm:ss"};
diff --git a/src/widget/form/settings/privacysettings.ui b/src/widget/form/settings/privacysettings.ui
index 84b4aecda..72262c327 100644
--- a/src/widget/form/settings/privacysettings.ui
+++ b/src/widget/form/settings/privacysettings.ui
@@ -43,11 +43,11 @@
-
- false
+
+
- Typing Notification
+ Send Typing Notifications
diff --git a/src/widget/friendlistwidget.cpp b/src/widget/friendlistwidget.cpp
index 176850e82..667143b3d 100644
--- a/src/widget/friendlistwidget.cpp
+++ b/src/widget/friendlistwidget.cpp
@@ -32,7 +32,7 @@ FriendListWidget::FriendListWidget(QWidget *parent) :
for (Status s : {Status::Online, Status::Away, Status::Busy, Status::Offline})
{
- QLayout *l = new QVBoxLayout();
+ QVBoxLayout *l = new QVBoxLayout();
l->setSpacing(0);
l->setMargin(0);
@@ -46,12 +46,12 @@ FriendListWidget::FriendListWidget(QWidget *parent) :
mainLayout->addLayout(layouts[static_cast(Status::Offline)], 4, 0);
}
-QLayout* FriendListWidget::getGroupLayout()
+QVBoxLayout* FriendListWidget::getGroupLayout()
{
return groupLayout;
}
-QLayout* FriendListWidget::getFriendLayout(Status s)
+QVBoxLayout* FriendListWidget::getFriendLayout(Status s)
{
auto res = layouts.find(static_cast(s));
if (res != layouts.end())
@@ -61,8 +61,11 @@ QLayout* FriendListWidget::getFriendLayout(Status s)
return layouts[static_cast(Status::Online)];
}
-void FriendListWidget::moveWidget(QWidget *w, Status s)
+void FriendListWidget::moveWidget(QWidget *w, Status s, int hasNewEvents)
{
mainLayout->removeWidget(w);
- getFriendLayout(s)->addWidget(w);
+ if (hasNewEvents == 0)
+ getFriendLayout(s)->addWidget(w);
+ else
+ getFriendLayout(s)->insertWidget(0, w);
}
diff --git a/src/widget/friendlistwidget.h b/src/widget/friendlistwidget.h
index ec44ba717..1dbddd45c 100644
--- a/src/widget/friendlistwidget.h
+++ b/src/widget/friendlistwidget.h
@@ -21,7 +21,7 @@
#include
#include "src/corestructs.h"
-class QLayout;
+class QVBoxLayout;
class QGridLayout;
class QPixmap;
@@ -31,17 +31,17 @@ class FriendListWidget : public QWidget
public:
explicit FriendListWidget(QWidget *parent = 0);
- QLayout* getGroupLayout();
- QLayout* getFriendLayout(Status s);
- void moveWidget(QWidget *w, Status s);
+ QVBoxLayout* getGroupLayout();
+ QVBoxLayout* getFriendLayout(Status s);
+ void moveWidget(QWidget *w, Status s, int hasNewEvents);
signals:
public slots:
private:
- QHash layouts;
- QLayout *groupLayout;
+ QHash layouts;
+ QVBoxLayout *groupLayout;
QGridLayout *mainLayout;
};
diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp
index 949024b29..7673bea4b 100644
--- a/src/widget/widget.cpp
+++ b/src/widget/widget.cpp
@@ -242,6 +242,7 @@ void Widget::init()
connect(core, &Core::avInvite, this, &Widget::playRingtone);
connect(core, &Core::blockingClearContacts, this, &Widget::clearContactsList, Qt::BlockingQueuedConnection);
connect(core, &Core::blockingGetPassword, this, &Widget::getPassword, Qt::BlockingQueuedConnection);
+ connect(core, &Core::friendTypingChanged, this, &Widget::onFriendTypingChanged);
connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int)));
connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int)));
@@ -318,6 +319,7 @@ Widget::~Widget()
coreThread->wait(500); // In case of deadlock (can happen with QtAudio/PA bugs)
if (!coreThread->isFinished())
coreThread->terminate();
+ AutoUpdater::abortUpdates();
delete core;
delete settingsWidget;
delete addFriendForm;
@@ -722,7 +724,7 @@ void Widget::onFriendStatusChanged(int friendId, Status status)
if (!f)
return;
- contactListWidget->moveWidget(f->getFriendWidget(), status);
+ contactListWidget->moveWidget(f->getFriendWidget(), status, f->getEventFlag());
bool isActualChange = f->getStatus() != status;
@@ -1176,6 +1178,14 @@ void Widget::getPassword(QString info, int passtype, uint8_t* salt)
}
}
+void Widget::onFriendTypingChanged(int friendId, bool isTyping)
+{
+ Friend* f = FriendList::findFriend(friendId);
+ if (!f)
+ return;
+ f->getChatForm()->setFriendTyping(isTyping);
+}
+
void Widget::onSetShowSystemTray(bool newValue){
icon->setVisible(newValue);
}
diff --git a/src/widget/widget.h b/src/widget/widget.h
index dd6bb3d94..ad6ad8b04 100644
--- a/src/widget/widget.h
+++ b/src/widget/widget.h
@@ -132,6 +132,7 @@ private slots:
void onIconClick(QSystemTrayIcon::ActivationReason);
void onUserAwayCheck();
void getPassword(QString info, int passtype, uint8_t* salt);
+ void onFriendTypingChanged(int friendId, bool isTyping);
void onSetShowSystemTray(bool newValue);
void onSplitterMoved(int pos, int index);
diff --git a/translations/i18n.pri b/translations/i18n.pri
index 668a89f07..d76b12b0c 100644
--- a/translations/i18n.pri
+++ b/translations/i18n.pri
@@ -11,7 +11,8 @@ TRANSLATIONS = translations/es.ts \
translations/pl.ts \
translations/ru.ts \
translations/sv.ts \
- translations/uk.ts
+ translations/uk.ts \
+ translations/pt.ts
#rules to generate ts
isEmpty(QMAKE_LUPDATE) {
diff --git a/translations/it.ts b/translations/it.ts
index 0d76e67b6..116745236 100644
--- a/translations/it.ts
+++ b/translations/it.ts
@@ -187,67 +187,72 @@ Ignorare le impostazioni del proxy e connettersi direttamente alla rete Tox?
ChatForm
-
+ Load History...Carica log...
-
+ Send a fileInvia un file
-
+ File not readImpossibile leggere il file
-
+ qTox wasn't able to open %1qTox non è riuscito ad aprire %1
-
+ Bad IdeaPessima idea
-
+ You're trying to send a special (sequential) file, that's not going to work!Stai cercando di inviare un file speciale (sequenziale), questo non funzionerà!
-
+ %1 is calling%1 ti sta chiamando
-
+ %1 stopped calling%1 ha fermato la chiamata
-
+ Calling to %1Stai chiamando %1
-
+ Failed to send file "%1"Invio del file "%1" fallito
-
+ Call with %1 ended. %2Chiamata con %1 terminata. %2
-
+ Call duration: Durata chiamata:
-
+
+ is typing...
+ sta scrivendo...
+
+
+ Call rejectedChiamata rifiutata
@@ -801,7 +806,7 @@ Soprannome:
Rimuovi messaggi visualizzati
-
+ ClearedPulito
@@ -1173,8 +1178,8 @@ Vuoi eliminare il vecchio file?
PrivacySettings
- Typing Notification
- Notifica quando qualcuno sta scrivendo
+ Send Typing Notifications
+ Permetti ai miei contatti di vedere quando sto scrivendo
@@ -1255,13 +1260,13 @@ Vuoi eliminare il vecchio file?
%1.tox è stato importato con successo
-
+ UpdateThe title of a message boxNuova versione
-
+ An update is available, do you want to download it now?
It will be installed when qTox restarts.È disponibile una nuova versione di qTox, vuoi scaricarla adesso?
@@ -1372,6 +1377,15 @@ Verrà installata al riavvio del programma.Error with the DNSLa risposta del server DNS non contiene un Tox ID valido
+
+
+
+ It appears that qTox has to use the old tox1 protocol.
+Unfortunately tox1 is not secure. Should it be used anyway?
+ Sembra che qTox debba usare il vecchio protocollo tox1.
+Sfortunatamente il protocollo tox1 non è sicuro.
+Usare comunque il protocollo tox1?
+ ToxURIDialog
@@ -1450,116 +1464,116 @@ Verrà installata al riavvio del programma.
Occupato
-
+ Choose a profileScegli un profilo
-
+ Please choose which identity to usePer favore scegli quale identità usare
-
+ Choose a profile pictureScegli un'immagine per il profilo
-
-
-
+
+
+ ErrorErrore
-
+ Unable to open this fileImpossibile aprire il file
-
+ Unable to read this imageImpossibile leggere l'immagine
-
+ This image is too bigL'immagine è troppo grande
-
+ Toxcore failed to start, the application will terminate after you close this message.Impossibile avviare Toxcore.\nqTox terminerà dopo che avrai chiuso questo messaggio.
-
+ toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.popup textImpossibile avviare Toxcore con le tue impostazione proxy.\nqTox non può funzionare correttamente, per favore modifica le impostazioni e riavvia il programma.
-
+ Add friendAggiungi contatto
-
+ File transfersFiles trasferiti
-
+ SettingsImpostazioni
-
+ Couldn't request friendshipImpossibile inviare la richiesta d'amicizia
-
+ awaycontact statusassente
-
+ busycontact statusoccupato
-
+ offlinecontact statusoffline
-
+ onlinecontact statusonline
-
+ %1 is now %2e.g. "Dubslow is now online"%1 è ora %2
-
+ <Unknown>Placeholder when we don't know someone's name in a group chat<Sconosciuto>
-
+ %1 has set the title to %2%1 ha impostato il titolo in %2
-
+ Message failed to sendImpossibile inviare il messaggio
diff --git a/translations/pt.ts b/translations/pt.ts
new file mode 100644
index 000000000..47792278d
--- /dev/null
+++ b/translations/pt.ts
@@ -0,0 +1,1578 @@
+
+
+
+
+ AVForm
+
+
+ Audio/Video
+ Áudio/Vídeo
+
+
+
+ AVSettings
+
+
+ Audio Settings
+ Configurações de Áudio
+
+
+
+ Microphone
+ Volume do Microfone
+
+
+
+ Playback
+ Volume de Reprodução
+
+
+
+ Playback device
+ Dispositivo de Reprodução
+
+
+
+ Capture device
+ Dispositivo de Captura
+
+
+
+ Rescan audio devices
+ Atualizar dispositivos de áudio
+
+
+
+ Filter audio
+ Filtrar áudio
+
+
+
+ Video Settings
+ Configurações de Vídeo
+
+
+
+ Resolution
+ Resolução
+
+
+
+ Hue
+ Matiz
+
+
+
+ Brightness
+ Brilho
+
+
+
+ Saturation
+ Saturação
+
+
+
+ Contrast
+ Contraste
+
+
+
+ AddFriendForm
+
+
+ Add Friends
+ Adicionar Contatos
+
+
+
+ Tox ID
+ Tox ID of the person you're sending a friend request to
+ ID Tox
+
+
+
+ Message
+ The message you send in friend requests
+ Mensagem
+
+
+
+ Send friend request
+ Enviar requisição de contato
+
+
+
+ Tox me maybe?
+ Default message in friend requests if the field is left blank. Write something appropriate!
+ Olá! Gostaria de adicionar você aos meus contatos no Tox.
+
+
+
+ Please fill in a valid Tox ID
+ Tox ID of the friend you're sending a friend request to
+ Por favor preencha um ID Tox válido
+
+
+
+ You can't add yourself as a friend!
+ When trying to add your own Tox ID as friend
+ Você não pode adicionar a si mesmo como contato!
+
+
+
+ qTox needs to use the Tox DNS, but can't do it through a proxy.
+Ignore the proxy and connect to the Internet directly?
+ qTox precisa usar o DNS do Tox, mas não pe capaz de fazer isso através de um proxy.
+Deve-se ignorar as configurações de proxy e conectar diretamente à internet?
+
+
+
+ This Tox ID does not exist
+ DNS error
+ Este ID Tox não existe
+
+
+
+ AdvancedForm
+
+
+ Advanced
+ Avançado
+
+
+
+ FULL - very safe, slowest (recommended)
+ COMPLETO - muito seguro, lento (recomendado)
+
+
+
+ NORMAL - almost as safe as FULL, about 20% faster than FULL
+ NORMAL - praticamente tão seguro quanto o COMPLETO, cerca de 20% mais rápido que o completo
+
+
+
+ OFF - disables all safety, when something goes wrong your history may be lost, fastest (not recommended)
+ DESLIGADO - desabilita toda a segurança, quando algo de errado ocorre seu histórico pode ser perdido, é o mais rápido (não recomendado)
+
+
+
+ AdvancedSettings
+
+
+ Form
+ Avançado
+
+
+
+ <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">IMPORTANT NOTE</span></p><p><span style=" color:#ff0000;">Unless you </span><span style=" font-weight:600; color:#ff0000;">really</span><span style=" color:#ff0000;"> know what you are doing, please do </span><span style=" font-weight:600; color:#ff0000;">not</span><span style=" color:#ff0000;"> change anything here. Changes made here may lead to problems with qTox, and even to loss of your data, e.g. history.</span></p></body></html>
+ <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">IMPORTANTE</span></p><p><span style=" color:#ff0000;">A menos que você </span><span style=" font-weight:600; color:#ff0000;">realmente</span><span style=" color:#ff0000;"> saiba o que está fazendo, por favor </span><span style=" font-weight:600; color:#ff0000;">não</span><span style=" color:#ff0000;"> altere nada aqui. Alterações feitas aqui podem causar problemas ao qTox, e mesmo a perda de seus dados, com seu histórico, por exemplo.</span></p></body></html>
+
+
+
+ Reset to default settings
+ Restaurar às configurações padrão
+
+
+
+ History
+ Histórico
+
+
+
+ <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Synchronous writing to DB</span></a></p></body></html>
+ <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Escrita sincronizada no BD</span></a></p></body></html>
+
+
+
+ ChatForm
+
+
+ Load History...
+ Carregar Histórico...
+
+
+
+ Send a file
+ Enviar um arquivo
+
+
+
+ File not read
+ Arquivo não lido
+
+
+
+ qTox wasn't able to open %1
+ qTox não foi capaz de abrir %1
+
+
+
+ Bad Idea
+ Má Idéia
+
+
+
+ You're trying to send a special (sequential) file, that's not going to work!
+ Você está tentando enviar um arquivo especial (sequencial), isso não vai funcionar!
+
+
+
+ %1 is calling
+ %1 está chamando
+
+
+
+ %1 stopped calling
+ %1 cancelou a chamada
+
+
+
+ Calling to %1
+ Chamando %1
+
+
+
+ Call rejected
+ Chamada rejeitada
+
+
+
+ Failed to send file "%1"
+ Falha ao enviar o arquivo "%1"
+
+
+
+ Call with %1 ended. %2
+ Chamada para %1 terminada. %2
+
+
+
+ Call duration:
+ Duração da chamada:
+
+
+
+ is typing...
+ está digitando...
+
+
+
+ ChatTextEdit
+
+
+ Type your message here...
+ Digite sua mensagem aqui...
+
+
+
+ Core
+
+
+ Toxing on qTox
+ Toxing on qTox
+
+
+
+ qTox User
+ Usuário do qTox
+
+
+
+ Friend is already added
+ Contato já adicionado
+
+
+
+ Encryption error
+ Erro de criptografia
+
+
+
+ The .tox file is encrypted, but encryption was not checked, continuing regardless.
+ O arquivo .tox é criptografado, mas a critpografia não foi verificada, continuando mesmo assim.
+
+
+
+ Tox datafile decryption password
+ Senha de criptografia do arquivo de dados
+
+
+
+
+
+ Password error
+ Senha incorreta
+
+
+
+
+ Failed to setup password.
+Empty password.
+ Falha na definição da senha.
+Senha em branco.
+
+
+
+ Try Again
+ Tente novamente
+
+
+
+ Change profile
+ Mudar perfil
+
+
+
+ Reinit current profile
+ Reiniciar o perfil atual
+
+
+
+ Wrong password has been entered
+ Senha incorreta fornecida
+
+
+
+ History Log decryption password
+ Senha de criptografia do arquivo de histórico
+
+
+
+ Encrypted log
+ Histórico criptografado
+
+
+
+ Your history is encrypted with different password.
+Do you want to try another password?
+ Seu histórico foi criptografado com uma senha diferente.
+Você quer tentar outra senha?
+
+
+
+ History
+ Histórico
+
+
+
+ Due to incorret password history will be disabled.
+ Devido à senha incorreta, o histórico será desabilitado.
+
+
+
+ NO Password
+ SEM senha
+
+
+
+ Will be saved without encryption!
+ Será armazenado sem criptografia!
+
+
+
+ FileTransferInstance
+
+
+ Save a file
+ Title of the file saving dialog
+ Salvar arquivo
+
+
+
+ Location not writable
+ Title of permissions popup
+ Impossível gravar aqui
+
+
+
+ You do not have permission to write that location. Choose another, or cancel the save dialog.
+ text of permissions popup
+ Você não possui permissão de escrita aqui. Escolha outro local ou cancele a operação.
+
+
+
+ ETA
+ Tempo
+
+
+
+ FilesForm
+
+
+ Transfered Files
+ "Headline" of the window
+ Arquivos transferidos
+
+
+
+ Downloads
+ Recebidos
+
+
+
+ Uploads
+ Enviados
+
+
+
+ FriendRequestDialog
+
+
+ Friend request
+ Title of the window to aceept/deny a friend request
+ Solicitação de contato
+
+
+
+ Someone wants to make friends with you
+ Alguém quer adicionar você como contato
+
+
+
+ User ID:
+ ID do usuário:
+
+
+
+ Friend request message:
+ Mensagem de requisição contato:
+
+
+
+ Accept
+ Accept a friend request
+ Aceitar
+
+
+
+ Reject
+ Reject a friend request
+ Rejeitar
+
+
+
+ FriendWidget
+
+
+ Invite to group
+ Menu to invite a friend to a groupchat
+ Convidar para grupo
+
+
+
+ Copy friend ID
+ Menu to copy the Tox ID of that friend
+ Copiar ID do contato
+
+
+
+ Set alias...
+ Apelido...
+
+
+
+ Auto accept files from this friend
+ context menu entry
+ Aceitar arquivos automaticamente deste contato
+
+
+
+ Remove friend
+ Menu to remove the friend from our friendlist
+ Remover contato
+
+
+
+ Choose an auto accept directory
+ popup title
+ Escolher um diretório para aceitar arquivos automaticamente
+
+
+
+ User alias
+ Apelido do usuário
+
+
+
+ You can also set this by clicking the chat form name.
+Alias:
+ Também pode ser definido clicando no nome do chat.
+Apelido:
+
+
+
+ GeneralForm
+
+
+ General
+ Geral
+
+
+
+
+ None
+ Nenhum
+
+
+
+ Choose an auto accept directory
+ popup title
+ Escolher um diretório para aceitar arquivos automaticamente
+
+
+
+ Call active
+ popup title
+ Chamada ativa
+
+
+
+ You can't disconnect while a call is active!
+ popup text
+ Você não pode desconectar enquanto uma chamada estiver ativa!
+
+
+
+ GeneralSettings
+
+
+ General Settings
+ Configurações Gerais
+
+
+
+
+ The translation may not load until qTox restarts.
+ A tradução pode não ser atualizada antes do qTox ser reinicializado.
+
+
+
+ Translation
+ Idioma
+
+
+
+ Save settings to the working directory instead of the usual conf dir
+ describes makeToxPortable checkbox
+ Armazena as configurações no diretório de trabalho ao invés do diretório de configurações usual
+
+
+
+ Make Tox portable
+ Deixe o Tox portável
+
+
+
+ System tray integration
+ Integração com a bandeja do sistema
+
+
+
+ Show system tray icon
+ Mostrar ícone na bandeja
+
+
+
+ Start in tray
+ Inicializar na bandeja
+
+
+
+ Close to tray
+ Fechar para a bandeja
+
+
+
+ Minimize to tray
+ Minimizar para a bandeja
+
+
+
+ Light icon
+ Ícone claro
+
+
+
+ Show contacts' status changes
+ Mostar alterações no status dos contatos
+
+
+
+ Check for updates on startup (unstable)
+ Checar atualizações na inicialização (instável)
+
+
+
+ Focus qTox when a message is received
+ Destacar o qTox quando receber uma mensagem
+
+
+
+ Faux offline messaging
+ Envio de mensagens "offline" falso
+
+
+
+ Provided in minutes
+ Em minutos
+
+
+
+ Auto away after (0 to disable)
+ Ficar ausente após (0 para desativar)
+
+
+
+ Set to 0 to disable
+ Defina 0 para desativar
+
+
+
+ minutes
+ minutos
+
+
+
+ You can set this on a per-friend basis by right clicking them.
+ autoaccept cb tooltip
+ Você pode definir esta configuração por contato clicando com o botão direito sobre eles.
+
+
+
+ Autoaccept files
+ Aceitar arquivos automaticamente
+
+
+
+ Save files in
+ Armazenar arquivos em
+
+
+
+ PushButton
+ Clique
+
+
+
+ Theme
+ Tema
+
+
+
+ Use emoticons
+ Usar emoticons
+
+
+
+ Smiley Pack
+ Text on smiley pack label
+ Conjunto de emoticons
+
+
+
+ Style
+ Estilo
+
+
+
+ Theme color
+ Cor do tema
+
+
+
+ Emoticon size
+ Tamanho do emoticon
+
+
+
+ px
+ px
+
+
+
+ Timestamp format
+ Formato da hora
+
+
+
+ Connection Settings
+ Configuraçẽs da Conexão
+
+
+
+ Enable IPv6 (recommended)
+ Text on a checkbox to enable IPv6
+ Permitir IPv6 (recomendado)
+
+
+
+ Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.
+ force tcp checkbox tooltip
+ Desabilitar esta opção permite, por exemplo, utilizar a rede Tor. Ela adiciona mais dados à rede Tor no entanto, portanto desmarque apenas se necessário.
+
+
+
+ Enable UDP (recommended)
+ Text on checkbox to disable UDP
+ Permitir UDP (recomendado)
+
+
+
+ Proxy type
+ Tipo de proxy
+
+
+
+ None
+ Nenum
+
+
+
+ SOCKS5
+ SOCKS5
+
+
+
+ HTTP
+ HTTP
+
+
+
+ Address
+ Text on proxy addr label
+ Endereço
+
+
+
+ Port
+ Text on proxy port label
+ Porta
+
+
+
+ Reconnect
+ reconnect button
+ Reconectar
+
+
+
+ GenericChatForm
+
+
+ Send message
+ Enviar mensagem
+
+
+
+ Smileys
+ Emoticons
+
+
+
+ Send file(s)
+ Enviar arquivo(s)
+
+
+
+ Audio call: RED means you're on a call
+ Chamada e áudio: VERMELHO significa que você está em uma chamada
+
+
+
+ Video call: RED means you're on a call
+ Chamada e vídeo: VERMELHO significa que você está em uma chamada
+
+
+
+ Toggle speakers volume: RED is OFF
+ Alternar volume de saída: VERMELHO é desligado
+
+
+
+ Toggle microphone: RED is OFF
+ Alternar volume de entrada: VERMELHO é desligado
+
+
+
+
+ Save chat log
+ Armazenar histórico da conversa
+
+
+
+ Clear displayed messages
+ Remover mensagens
+
+
+
+ Cleared
+ Removidas
+
+
+
+ GroupChatForm
+
+
+ %1 users in chat
+ Number of users in chat
+ %1 usuários no grupo
+
+
+
+ %1 users in chat
+ %1 usuários no grupo
+
+
+
+ GroupWidget
+
+
+
+ %1 users in chat
+ %1 usuários no grupo
+
+
+
+
+ 0 users in chat
+ nenhum usuário no grupo
+
+
+
+ Set title...
+ Defina o título...
+
+
+
+ Quit group
+ Menu to quit a groupchat
+ Sair do grupo
+
+
+
+ Group title
+ Título do grupo
+
+
+
+ You can also set this by clicking the chat form name.
+Title:
+ É possível definir clicando no nome do grupo.
+Título:
+
+
+
+ IdentityForm
+
+
+ Identity
+ Identidade
+
+
+
+ Call active
+ popup title
+ Chamada ativa
+
+
+
+ You can't switch profiles while a call is active!
+ popup text
+ Não é possível trocar de perfil enquanto uma chamada estiver ativa!
+
+
+
+ Rename "%1"
+ renaming a profile
+ Renomear "%1"
+
+
+
+ Profile already exists
+ rename confirm title
+ O perfil já existe
+
+
+
+ A profile named "%1" already exists. Do you want to erase it?
+ rename confirm text
+ Um perfil chamado "%1" já existe. Deseja sobrescrevê-lo?
+
+
+
+ Export profile
+ save dialog title
+ Esportar perfil
+
+
+
+ Tox save file (*.tox)
+ save dialog filter
+ Armazenar arquivo Tox (*.tox)
+
+
+
+ Failed to remove file
+ Falha ao remover o arquivo
+
+
+
+ The file you chose to overwrite could not be removed first.
+ O arquivo escolhido para sobrescrever não pôde ser removido.
+
+
+
+ Failed to copy file
+ Falha ao copiar o arquivo
+
+
+
+ The file you chose could not be written to.
+ O arquivo que você escolheu não pôde ser escrito.
+
+
+
+ Profile currently loaded
+ current profile deletion warning title
+ Perfil carregado no momento
+
+
+
+ This profile is currently in use. Please load a different profile before deleting this one.
+ current profile deletion warning text
+ Esper perfil está atualmente em uso. Por favor carrege outro perfil antes de excluir este.
+
+
+
+ Deletion imminent!
+ deletion confirmation title
+ Exclusão iminente!
+
+
+
+ Are you sure you want to delete this profile?
+Associated friend information and chat logs will be deleted as well.
+ deletion confirmation text
+ Tem certeza que deseja excuir este perfil? As informações de contatos e histórico também serão removidos.
+
+
+
+ Import profile
+ import dialog title
+ Importar perfil
+
+
+
+ Tox save file (*.tox)
+ import dialog filter
+ Arquivo Tox (*.tox)
+
+
+
+ Ignoring non-Tox file
+ popup title
+ Ignorando arquivo não Tox
+
+
+
+ Warning: you've chosen a file that is not a Tox save file; ignoring.
+ popup text
+ Atenção: foi escolhido um arquivo que não é um arquivo Tox. Ignorando.
+
+
+
+ Profile already exists
+ import confirm title
+ O perfil já existe
+
+
+
+ A profile named "%1" already exists. Do you want to erase it?
+ import confirm text
+ Um perfil chamado "%1" já existe. Deseja sobrescrevê-lo?
+
+
+
+ IdentitySettings
+
+
+ Public Information
+ Informações Públicas
+
+
+
+ Name
+ Nome
+
+
+
+ Status
+ Status
+
+
+
+ Tox ID
+ ID Tox
+
+
+
+ Your Tox ID (click to copy)
+ Seu ID Tox (clique para copiar)
+
+
+
+ Profiles
+ Perfis
+
+
+
+ Available profiles:
+ Perfis disponíveis:
+
+
+
+
+ Switching profiles is disabled during calls
+ tooltip
+ alternar entre perfis não está habilitado durante chamadas
+
+
+
+ Load
+ load profile button
+ Carregar
+
+
+
+ Rename
+ rename profile button
+ Renomear
+
+
+
+ Export
+ export profile button
+ Exportar
+
+
+
+ This is useful to remain safe on public computers
+ delete profile button tooltip
+ Útil para ficar seguro em computadores públicos
+
+
+
+ Delete
+ delete profile button
+ Excluir
+
+
+
+ Import a profile
+ import profile button
+ Importar um perfil
+
+
+
+ New Tox ID
+ new profile button
+ Novo ID Tox
+
+
+
+ InputPasswordDialog
+
+
+ Password Dialog
+ Senha
+
+
+
+ Input password:
+ Digite sua Senha:
+
+
+
+ LoadHistoryDialog
+
+
+ Load History Dialog
+ Carregar Histórico
+
+
+
+ Load history from:
+ Carregar histórico de:
+
+
+
+ MainWindow
+
+
+ Your name
+ Seu nome
+
+
+
+ Your status
+ Seu status
+
+
+
+ Add friends
+ Adicionar contatos
+
+
+
+ Create a group chat
+ Criar um grupo
+
+
+
+ View completed file transfers
+ Ver transferências de arquivos completadas
+
+
+
+ Change your settings
+ Alterar suas configurações
+
+
+
+ Close
+ Fechar
+
+
+
+ NetCamView
+
+
+ Tox video
+ Vídeo Tox
+
+
+
+ PrivacyForm
+
+
+ Privacy
+ Privacidade
+
+
+
+ Encrypted log
+ Histórico criptografado
+
+
+
+ You already have history log file encrypted with different password
+Do you want to delete old history file?
+ Seu histórico foi criptografado com uma senha diferente.
+Você quer remover este arquivo de histórico antigo?
+
+
+
+ PrivacySettings
+
+
+ Send Typing Notifications
+ Enviar notificação de digitação
+
+
+
+ Keep History (unstable)
+ Manter histórico (instável)
+
+
+
+ Encryption
+ Criptografia
+
+
+
+ Encrypt Tox datafile
+ Criptografar os arquivos Tox
+
+
+
+ Encrypt History
+ Criptografar histórico
+
+
+
+ Nospam
+ Anti-span
+
+
+
+ HHHHHHHH
+ HHHHHHHH
+
+
+
+ Generate random nospam
+ Gerar um número anti-span aleatório
+
+
+
+ QObject
+
+
+ Update
+ The title of a message box
+ Atualizar
+
+
+
+ An update is available, do you want to download it now?
+It will be installed when qTox restarts.
+ Uma atualização está disponível, você deseja baixá-la agora?
+Ela será instalada quando o qTox for reiniciado.
+
+
+
+ Tox URI to parse
+ UTI Tox para interpretar
+
+
+
+ Starts new instance and loads specified profile.
+ Inicia uma nova instância e carrega o perfil especificado.
+
+
+
+ profile
+ perfil
+
+
+
+ Default
+ Padrão
+
+
+
+ Blue
+ Azul
+
+
+
+ Olive
+ Verde-oliva
+
+
+
+ Red
+ Vermelho
+
+
+
+ Violet
+ Violeta
+
+
+
+ Ignoring non-Tox file
+ popup title
+ Ignorando arquivo não Tox
+
+
+
+ Warning: you've chosen a file that is not a Tox save file; ignoring.
+ popup text
+ Atenção: foi escolhido um arquivo que não é um arquivo Tox. Ignorando.
+
+
+
+ Profile already exists
+ import confirm title
+ O perfil já existe
+
+
+
+ A profile named "%1" already exists. Do you want to erase it?
+ import confirm text
+ Um perfil chamado "%1" já existe. Deseja sobrescrevê-lo?
+
+
+
+ Profile imported
+ Perfil importado
+
+
+
+ %1.tox was successfully imported
+ %1.tox importado com sucesso
+
+
+
+ Tox me maybe?
+ Default message in Tox URI friend requests. Write something appropriate!
+ Olá! Gostaria de adicionar você aos meus contatos no Tox.
+
+
+
+ SetPasswordDialog
+
+
+ Type Password
+ Digite a Senha
+
+
+
+ Repeat Password
+ Repita a Senha
+
+
+
+ ToxDNS
+
+
+ The connection timed out
+ The DNS gives the Tox ID associated to toxme.se addresses
+ O tempo da conexão expirou
+
+
+
+ This address does not exist
+ The DNS gives the Tox ID associated to toxme.se addresses
+ Este endereço não existe
+
+
+
+ Error while looking up DNS
+ The DNS gives the Tox ID associated to toxme.se addresses
+ Erro ao consultar o DNS
+
+
+
+ No text record found
+ Error with the DNS
+ Nenhum registro encontrado
+
+
+
+ Unexpected number of values in text record
+ Error with the DNS
+ Número de entradas inesperado
+
+
+
+ The version of Tox DNS used by this server is not supported
+ Error with the DNS
+ A versão do DNS Tox utilizada por este servidor não é suportada
+
+
+
+ The DNS lookup does not contain any Tox ID
+ Error with the DNS
+ A resposta do DNS não contém nenhum ID Tox
+
+
+
+
+ The DNS lookup does not contain a valid Tox ID
+ Error with the DNS
+ A resposta do DNS não contém um ID Tox válido
+
+
+
+
+ It appears that qTox has to use the old tox1 protocol.
+Unfortunately tox1 is not secure. Should it be used anyway?
+ parece que o qTox está usando o protocolo tox1 antigo.
+Infelizmente o tox1 não é seguro. Deve ele ser usado mesmo assim?
+
+
+
+ ToxURIDialog
+
+
+ Add a friend
+ Title of the window to add a friend through Tox URI
+ Adicionar um contato
+
+
+
+ Do you want to add %1 as a friend?
+ Você deseja adicionar %1 como seu contato?
+
+
+
+ User ID:
+ ID do usuário:
+
+
+
+ Friend request message:
+ Mensagem de requisição contato:
+
+
+
+ Send
+ Send a friend request
+ Enviar
+
+
+
+ Cancel
+ Don't send a friend request
+ Cancelar
+
+
+
+ Widget
+
+
+ Online
+ Online
+
+
+
+ Away
+ Ausente
+
+
+
+ Busy
+ Ocupado
+
+
+
+ &Quit
+ &Sair
+
+
+
+ Online
+ Button to set your status to 'Online'
+ Online
+
+
+
+ Away
+ Button to set your status to 'Away'
+ Ausente
+
+
+
+ Busy
+ Button to set your status to 'Busy'
+ Ocupado
+
+
+
+ Choose a profile
+ Escolha um perfil
+
+
+
+ Please choose which identity to use
+ Por favor escolha qual identidade usar
+
+
+
+ Choose a profile picture
+ Escolha uma imagem para o perfil
+
+
+
+
+
+ Error
+ Erro
+
+
+
+ Unable to open this file
+ Não foi possível abrir este arquivo
+
+
+
+ Unable to read this image
+ Não foi possível ler esta imagem
+
+
+
+ This image is too big
+ Esta imagem é muito grande
+
+
+
+ Toxcore failed to start, the application will terminate after you close this message.
+ O Toxcore falhou ao inicializar, a aplicação será finalizada assim que esta mensagem for fechada.
+
+
+
+ toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.
+ popup text
+ O Toxcore falhou ao inicializar suas configurações de proxy. O qTox não pode ser executado, por favor modifique suas configurações e reinicialize o aplicativo.
+
+
+
+ Add friend
+ Adicionar contato
+
+
+
+ File transfers
+ Transferências de arquivo
+
+
+
+ Settings
+ Configurações
+
+
+
+ Couldn't request friendship
+ Não foi possível adicionar o contato
+
+
+
+ away
+ contact status
+ ausente
+
+
+
+ busy
+ contact status
+ ocupado
+
+
+
+ offline
+ contact status
+ offline
+
+
+
+ online
+ contact status
+ online
+
+
+
+ %1 is now %2
+ e.g. "Dubslow is now online"
+ %1 agora é %2
+
+
+
+ <Unknown>
+ Placeholder when we don't know someone's name in a group chat
+ <Desconhecido>
+
+
+
+ %1 has set the title to %2
+ %1 alterou o título para %2
+
+
+
+ Message failed to send
+ Falha no envio da mensagem
+
+
+
diff --git a/translations/uk.ts b/translations/uk.ts
index a2ecf9015..51953bc5d 100644
--- a/translations/uk.ts
+++ b/translations/uk.ts
@@ -37,32 +37,42 @@
Пристрій захоплення
-
+
+ Rescan audio devices
+ Пересканувати аудіо пристрої
+
+
+
+ Filter audio
+ Фільтр звуку
+
+
+ Video SettingsПараметри відео
-
+ ResolutionРоздільна здатність
-
+ HueВідтінок
-
+ BrightnessЯскравість
-
+ SaturationНасиченість
-
+ ContrastКонтраст
@@ -112,7 +122,7 @@
qTox needs to use the Tox DNS, but can't do it through a proxy.
-Ignore the proxy and connect to the Internet directly ?
+Ignore the proxy and connect to the Internet directly?
qTox потребує Tox DNS, але не може скористатися ним через проксі.
Проігнорувати проксі та під'єднатися напряму?
@@ -177,52 +187,72 @@ Ignore the proxy and connect to the Internet directly ?
ChatForm
-
+ Load History...Завантажити історію…
-
+ Send a fileНадіслати файл
-
+
+ File not read
+ Файл не читається
+
+
+
+ qTox wasn't able to open %1
+ qTox не може відкрити файл %1
+
+
+ Bad IdeaПогана ідея
-
+ You're trying to send a special (sequential) file, that's not going to work!Ви намагаєтесь передати спеціальний (послідовний) файл, це не так працює!
-
- %1 calling
- %1 викликає
+
+ %1 is calling
+ %1 дзвонить
-
+ %1 stopped calling%1 припинив виклик
-
+ Calling to %1Викликаємо %1
-
+
+ Failed to send file "%1"
+ Не вдалось відправити файл «%1»
+
+
+ Call with %1 ended. %2Виклик із %1 завершено. %2
-
+ Call duration: Тривалість дзвінка:
-
+
+ is typing...
+ набирає...
+
+
+ Call rejectedДзвінок відхилено
@@ -238,104 +268,104 @@ Ignore the proxy and connect to the Internet directly ?
Core
-
+ Toxing on qToxВітання з qTox
-
+ qTox UserКористувач qTox
-
+ Friend is already addedДруга вже додано
-
+ Encryption errorПомилка шифрування
-
+ The .tox file is encrypted, but encryption was not checked, continuing regardless.Файл .tox зашифровано, але шифрування не перевірено, попри це продовжуємо.
-
+ Tox datafile decryption passwordРозшифрування файлу даних Tox
-
-
-
+
+
+ Password errorПомилка паролю
-
-
+
+ Failed to setup password.
Empty password.Не вдалось встановити пароль.
Пароль пустий.
-
+ Try AgainСпробуйте ще раз
-
+ Change profileЗмінити профіль
-
+ Reinit current profileПере ініціалізувати поточний профіль
-
+ Wrong password has been enteredВведено хибний пароль
-
+ History Log decryption passwordРозшифрування історії
-
- Your history is encrypted with different password
+
+ Your history is encrypted with different password.
Do you want to try another password?
- Ваша історія зашифрована інакшим паролем
+ Ваша історія зашифрована інакшим паролем.
Бажаєте спробувати інший пароль?
-
+
+ History
+ Історія
+
+
+
+ Due to incorret password history will be disabled.
+ Введено некоректний пароль, звітування вимкнено.
+
+
+ Encrypted logЗашифрований звіт
-
- Loggin
- Звітування
-
-
-
- Due to incorret password logging will be disabled
- Введено некоректний пароль, звітування вимкнено
-
-
-
+ NO PasswordВідсутній пароль
-
+ Will be saved without encryption!Буде збережено без шифрування!
@@ -447,14 +477,16 @@ Do you want to try another password?
Автоматично приймати файли від даного друга
-
+ User aliasПсевдонім користувача
-
- Alias:
- Псевдонім:
+
+ You can also set this by clicking the chat form name.
+Alias:
+ Ви також можете встановити його натиснувши на назву форми в чаті.
+Псевдонім:
@@ -477,25 +509,25 @@ Do you want to try another password?
Основні
-
-
+
+ NoneВідсутній
-
+ Choose an auto accept directorypopup titleОберіть теку, для автоматичного отримання файлів
-
+ Call activepopup titleДзвінок активний
-
+ You can't disconnect while a call is active!popup textВи не можете від'єднатись під час активного дзвінка!
@@ -526,47 +558,52 @@ Do you want to try another password?
Портативний запуск
-
- Show system tray icon
- Показувати піктрограму в системному лотку
+
+ System tray integration
+ Інтеграція із системним лотком
-
+
+ Show system tray icon
+ Показувати піктограму в системному лотку
+
+
+ Start in trayЗапускати у системному лотку
-
+ Close to trayЗакривати до лотку
-
+ Minimize to trayМінімізувати до лотку
-
+ Show contacts' status changesПоказувати зміну статусів контактів
-
+ Provided in minutesВстановлено в хвилинах
-
+ Set to 0 to disableВстановіть 0, аби вимкнути
-
+ minutes хвилин
-
+ ThemeГрафічна тема
@@ -576,128 +613,148 @@ Do you want to try another password?
Мова інтерфейсу
- Show system tray
- Показувати в системному лотку
+
+ Light icon
+ Світлі піктограми
-
+ Check for updates on startup (unstable)Перевіряти оновлення під час запуску (нестабільна функція)
-
+ Focus qTox when a message is receivedПерехоплювати фокус вікна при отриманні повідомлення
-
+ Faux offline messagingФальшивий поза мережевий обмін повідомленнями
-
+ Auto away after (0 to disable)Авто-статус «Відійшов» (0=вимкнено)
-
+ You can set this on a per-friend basis by right clicking them.autoaccept cb tooltip
-
+ Ви також можете встановити це значення до кожного друга окремо викликавши правою кнопкою меню навпроти нього.
-
+ Autoaccept filesАвтоматично приймати файли
-
+ Save files inЗберігати файли до
-
+ PushButtonТисніть кнопку
-
+ Use emoticonsВикористовувати смайлики
-
+ Smiley PackText on smiley pack labelПакунок смайликів
-
+ StyleСтиль
-
+ Theme colorКолір графічної теми
-
+ Emoticon sizeРозмір смайликів
-
+ px px
-
+ Timestamp formatФормати часового відбитку
-
+ Connection SettingsПараметри підключення
-
+ Enable IPv6 (recommended)Text on a checkbox to enable IPv6Дозволити IPv6 (рекомендовано)
-
+ Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.force tcp checkbox tooltip
-
+ Enable UDP (recommended)Text on checkbox to disable UDPДозволити UDP (рекомендовано)
-
- Use proxy (SOCKS5)
- Використовувати проксі (SOCKS5)
+
+ Proxy type
+ Тип проксі
-
+
+ None
+ Відсутній
+
+
+
+ SOCKS5
+ SOCKS5
+
+
+
+ HTTP
+ HTTP
+
+
+ Use proxy (SOCKS5)
+ Використовувати проксі (SOCKS5)
+
+
+ AddressText on proxy addr labelАдреса
-
+ PortText on proxy port labelПорт
-
+ Reconnectreconnect buttonПовторно під'єднатись
@@ -706,53 +763,53 @@ Do you want to try another password?
GenericChatForm
-
+ Send messageВідправити повідомлення
-
+ SmileysСмайлики
-
+ Send file(s)Відправити файл(и)
-
+ Audio call: RED means you're on a callАудіо дзвінок: Червоний - дзвінок активний
-
+ Video call: RED means you're on a callВідео дзвінок: Червоний - дзвінок активний
-
+ Toggle speakers volume: RED is OFFПеремкнути стан гучності відтворення: Червоний - вимкнено
-
+ Toggle microphone: RED is OFFПеремкнути рівень підсилення мікрофону: Червоний - вимкнено
-
-
+
+ Save chat logЗберегти чат
-
+ Clear displayed messagesОчистити показані повідомлення
-
+ ClearedОчищено
@@ -760,13 +817,13 @@ Do you want to try another password?
GroupChatForm
-
+ %1 users in chatNumber of users in chatКористувачів у чаті: %1
-
+ %1 users in chatКористувачів у чаті: %1
@@ -774,23 +831,40 @@ Do you want to try another password?
GroupWidget
-
-
+
+ %1 users in chatКористувачів у чаті: %1
-
-
+
+ 0 users in chatНемає користувачів
-
+ Quit groupMenu to quit a groupchatВийти з групи
+
+
+ Set title...
+ Встановити заголовок…
+
+
+
+ Group title
+ Заголовок групи
+
+
+
+ You can also set this by clicking the chat form name.
+Title:
+ Ви також можете встановити його натиснувши на назву форми в чаті.
+Заголовок:
+ IdentityForm
@@ -881,42 +955,44 @@ Do you want to try another password?
- Are you sure you want to delete this profile?
+ Are you sure you want to delete this profile?
+Associated friend information and chat logs will be deleted as well.deletion confirmation text
- Дійсно вилучити даний профіль?
+ Дійсно вилучити даний профіль?
+Пов'язана інформація про друзів та історія спілкування також буде вилучена.
-
+ Import profileimport dialog titleІмпортувати профіль
-
+ Tox save file (*.tox)import dialog filterФайл збереження Tox (*.tox)
-
+ Ignoring non-Tox filepopup titleІгнорування не Tox файлу
-
+ Warning: you've chosen a file that is not a Tox save file; ignoring.popup textУвага: вказаний вами файл не є файлом збереження Tox; ігнорую.
-
+ Profile already existsimport confirm titleПрофіль вже існує
-
+ A profile named "%1" already exists. Do you want to erase it?import confirm textПрофіль із назвою «%1» вже існує. Бажаєте стерти його?
@@ -1104,9 +1180,13 @@ Do you want to delete old history file?
PrivacySettings
- Typing Notification
- Увімкнути сповіщення про набір
+ Увімкнути сповіщення про набір
+
+
+
+ Send Typing Notifications
+ Надсилати сповіщення про набір
@@ -1187,14 +1267,14 @@ Do you want to delete old history file?
%1.tox успішно імпортовано
-
+ UpdateThe title of a message boxОновити
-
- An update is available, do you want to download it now ?
+
+ An update is available, do you want to download it now?
It will be installed when qTox restarts.Доступне оновлення, бажаєте завантажити його зараз?
Оновлення буде встановлено після перезапуску qTox.
@@ -1204,6 +1284,16 @@ It will be installed when qTox restarts.Tox URI to parseTox URI для розбору
+
+
+ Starts new instance and loads specified profile.
+
+
+
+
+ profile
+ профіль
+ Default
@@ -1294,6 +1384,13 @@ It will be installed when qTox restarts.
Error with the DNSВідповідь DNS не містить жодного коректного Tox ID
+
+
+
+ It appears that qTox has to use the old tox1 protocol.
+Unfortunately tox1 is not secure. Should it be used anyway?
+
+ ToxURIDialog
@@ -1305,7 +1402,7 @@ It will be installed when qTox restarts.
- Do you want to add %1 as a friend ?
+ Do you want to add %1 as a friend?Бажаєте додати %1 як друга?
@@ -1334,159 +1431,158 @@ It will be installed when qTox restarts.
Widget
-
+ OnlineВ мережі
-
+ AwayВідійшов
-
+ BusyЗайнятий
-
+ &Quit&Вийти
- Change status to:
- Змінити статус на:
+ Змінити статус на:
-
+ OnlineButton to set your status to 'Online'В мережі
-
+ AwayButton to set your status to 'Away'Відійшов
-
+ BusyButton to set your status to 'Busy'Зайнятий
-
+ Choose a profileОберіть профіль
-
+ Please choose which identity to useОберіть ідентифікатор для використання
-
+ Choose a profile pictureОберіть зображення для профілю
-
-
-
+
+
+ ErrorПомилка
-
+ Unable to open this fileНеможливо відкрити цей файл
-
+ Unable to read this imageНеможливо прочитати це зображення
-
+ This image is too bigЗображення завелике
-
+ Toxcore failed to start, the application will terminate after you close this message.Помилка запуску ядра tox, програма буде завершена після закриття цього повідомлення.
-
+ toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.popup textПомилка запуску ядра tox із поточними параметрами проксі. qTox не працює; змініть параметри і перезапустіть.
-
+ Add friendДодати друга
-
+ File transfersПередачі файлів
-
+ SettingsПараметри
-
+ Couldn't request friendshipНе вдалось надіслати запит на дружбу
-
+ awaycontact statusВідійшов
-
+ busycontact statusЗайнятий
-
+ offlinecontact statusПоза мережею
-
+ onlinecontact statusВ мережі
-
+ %1 is now %2e.g. "Dubslow is now online"%1 тепер вже відомий як %2
-
+ <Unknown>Placeholder when we don't know someone's name in a group chat<Невідомо>
-
+ %1 has set the title to %2%1 встановив тему %2
-
+ Message failed to sendНе вдалось відправити повідомлення