mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'master' into chatlog_v3_1
Conflicts: src/widget/chatareawidget.cpp src/widget/form/chatform.h src/widget/form/genericchatform.cpp
This commit is contained in:
commit
d9e15fb0ba
|
@ -37,6 +37,6 @@ This client runs on Windows, Linux and Mac natively.<br/>
|
|||
|
||||
##Developer overview:
|
||||
|
||||
[GitStats](http://207.12.89.155/index.html)<br/>
|
||||
[GitStats](http://104.219.184.93/index.html)<br/>
|
||||
[Mac & Linux jenkins](https://jenkins.libtoxcore.so/user/tux3/my-views/view/qTox/)<br/>
|
||||
[Windows jenkins](http://207.12.89.155:8080)<br/>
|
||||
[Windows jenkins](http://104.219.184.93:8080)<br/>
|
||||
|
|
8
qtox.pro
8
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
|
||||
|
|
1
res.qrc
1
res.qrc
|
@ -127,6 +127,7 @@
|
|||
<file>translations/mannol.qm</file>
|
||||
<file>translations/pirate.qm</file>
|
||||
<file>translations/pl.qm</file>
|
||||
<file>translations/pt.qm</file>
|
||||
<file>translations/ru.qm</file>
|
||||
<file>translations/sv.qm</file>
|
||||
<file>translations/uk.qm</file>
|
||||
|
|
130
src/audio.cpp
130
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 <QDebug>
|
||||
#include <QThread>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
std::atomic<int> 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: "<<msg;
|
||||
#endif
|
||||
}
|
||||
|
||||
Audio& Audio::getInstance()
|
||||
{
|
||||
if (!instance)
|
||||
|
@ -39,6 +57,8 @@ Audio& Audio::getInstance()
|
|||
audioThread = new QThread(instance);
|
||||
audioThread->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;
|
||||
}
|
||||
|
|
|
@ -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<int> userCount;
|
||||
static ALCdevice* alOutDev, *alInDev;
|
||||
static QMutex* audioInLock, *audioOutLock;
|
||||
};
|
||||
|
||||
#endif // AUDIO_H
|
||||
|
|
|
@ -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<UpdateFileMeta> newFlist = parseFlist(newFlistData);
|
||||
QList<UpdateFileMeta> diff = genUpdateDiff(newFlist);
|
||||
|
||||
if (abortFlag)
|
||||
return false;
|
||||
|
||||
qDebug() << "AutoUpdater: Need to update "<<diff.size()<<" files";
|
||||
|
||||
// Create an empty directory to download updates into
|
||||
|
@ -308,6 +316,9 @@ bool AutoUpdater::downloadUpdate()
|
|||
// Download and write each new file
|
||||
for (UpdateFileMeta fileMeta : diff)
|
||||
{
|
||||
if (abortFlag)
|
||||
return false;
|
||||
|
||||
qDebug() << "AutoUpdater: Downloading '"+fileMeta.installpath+"' ...";
|
||||
|
||||
// Create subdirs if necessary
|
||||
|
@ -317,6 +328,8 @@ bool AutoUpdater::downloadUpdate()
|
|||
|
||||
// Download
|
||||
UpdateFile file = getUpdateFile(fileMeta);
|
||||
if (abortFlag)
|
||||
return false;
|
||||
if (file.data.isNull())
|
||||
{
|
||||
qWarning() << "AutoUpdater::downloadUpdate: Error downloading a file, aborting...";
|
||||
|
@ -357,7 +370,7 @@ bool AutoUpdater::isLocalUpdateReady()
|
|||
if (!updateDir.exists())
|
||||
return false;
|
||||
|
||||
// Check that we have a flist and that every file on the diff exists
|
||||
// Check that we have a flist and generate a diff
|
||||
QFile updateFlistFile(updateDirStr+"flist");
|
||||
if (!updateFlistFile.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
|
@ -367,9 +380,23 @@ bool AutoUpdater::isLocalUpdateReady()
|
|||
QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData);
|
||||
QList<UpdateFileMeta> 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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*>(_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*>(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*>(core)->avStarting(friendId, call_index, false);
|
||||
// }
|
||||
|
||||
// delete transSettings;
|
||||
//}
|
||||
|
||||
//void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
|
||||
//{
|
||||
// ToxAv* toxav = static_cast<ToxAv*>(_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*>(core)->avEnding(friendId, call_index);
|
||||
//}
|
||||
|
||||
void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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<QVBoxLayout*>(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();
|
||||
|
|
|
@ -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<uint, FileTransferInstance*> ftransWidgets;
|
||||
void startCounter();
|
||||
|
@ -106,6 +109,7 @@ private:
|
|||
QString secondsToDHMS(quint32 duration);
|
||||
QHash<int, int> receipts;
|
||||
QMap<int, ChatMessage::Ptr> undeliveredMsgs;
|
||||
bool isTyping;
|
||||
};
|
||||
|
||||
#endif // CHATFORM_H
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"};
|
||||
|
||||
|
|
|
@ -43,11 +43,11 @@
|
|||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbTypingNotification">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<property name="toolTip">
|
||||
<string extracomment="Your friends will be able to see when you are typing."/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Typing Notification</string>
|
||||
<string>Send Typing Notifications</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -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<int>(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<int>(s));
|
||||
if (res != layouts.end())
|
||||
|
@ -61,8 +61,11 @@ QLayout* FriendListWidget::getFriendLayout(Status s)
|
|||
return layouts[static_cast<int>(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);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <QHash>
|
||||
#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<int, QLayout*> layouts;
|
||||
QLayout *groupLayout;
|
||||
QHash<int, QVBoxLayout*> layouts;
|
||||
QVBoxLayout *groupLayout;
|
||||
QGridLayout *mainLayout;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
3
translations/i18n.pri
vendored
3
translations/i18n.pri
vendored
|
@ -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) {
|
||||
|
|
96
translations/it.ts
vendored
96
translations/it.ts
vendored
|
@ -187,67 +187,72 @@ Ignorare le impostazioni del proxy e connettersi direttamente alla rete Tox?</tr
|
|||
<context>
|
||||
<name>ChatForm</name>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="66"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="75"/>
|
||||
<source>Load History...</source>
|
||||
<translation>Carica log...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="137"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="162"/>
|
||||
<source>Send a file</source>
|
||||
<translation>Invia un file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="145"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="170"/>
|
||||
<source>File not read</source>
|
||||
<translation>Impossibile leggere il file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="145"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="170"/>
|
||||
<source>qTox wasn't able to open %1</source>
|
||||
<translation>qTox non è riuscito ad aprire %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="150"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="175"/>
|
||||
<source>Bad Idea</source>
|
||||
<translation>Pessima idea</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="150"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="175"/>
|
||||
<source>You're trying to send a special (sequential) file, that's not going to work!</source>
|
||||
<translation>Stai cercando di inviare un file speciale (sequenziale), questo non funzionerà!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="257"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="283"/>
|
||||
<source>%1 is calling</source>
|
||||
<translation>%1 ti sta chiamando</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="328"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="356"/>
|
||||
<source>%1 stopped calling</source>
|
||||
<translation>%1 ha fermato la chiamata</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="384"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="413"/>
|
||||
<source>Calling to %1</source>
|
||||
<translation>Stai chiamando %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="676"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="705"/>
|
||||
<source>Failed to send file "%1"</source>
|
||||
<translation>Invio del file "%1" fallito</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="810"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="839"/>
|
||||
<source>Call with %1 ended. %2</source>
|
||||
<translation>Chiamata con %1 terminata. %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="829"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="858"/>
|
||||
<source>Call duration: </source>
|
||||
<translation>Durata chiamata: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="525"/>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="905"/>
|
||||
<source>is typing...</source>
|
||||
<translation>sta scrivendo...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/chatform.cpp" line="554"/>
|
||||
<source>Call rejected</source>
|
||||
<translation>Chiamata rifiutata</translation>
|
||||
</message>
|
||||
|
@ -801,7 +806,7 @@ Soprannome:</translation>
|
|||
<translation>Rimuovi messaggi visualizzati</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/genericchatform.cpp" line="296"/>
|
||||
<location filename="../src/widget/form/genericchatform.cpp" line="297"/>
|
||||
<source>Cleared</source>
|
||||
<translation>Pulito</translation>
|
||||
</message>
|
||||
|
@ -1173,8 +1178,8 @@ Vuoi eliminare il vecchio file?</translation>
|
|||
<name>PrivacySettings</name>
|
||||
<message>
|
||||
<location filename="../src/widget/form/settings/privacysettings.ui" line="50"/>
|
||||
<source>Typing Notification</source>
|
||||
<translation>Notifica quando qualcuno sta scrivendo</translation>
|
||||
<source>Send Typing Notifications</source>
|
||||
<translation>Permetti ai miei contatti di vedere quando sto scrivendo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/form/settings/privacysettings.ui" line="60"/>
|
||||
|
@ -1255,13 +1260,13 @@ Vuoi eliminare il vecchio file?</translation>
|
|||
<translation>%1.tox è stato importato con successo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/autoupdate.cpp" line="430"/>
|
||||
<location filename="../src/autoupdate.cpp" line="457"/>
|
||||
<source>Update</source>
|
||||
<comment>The title of a message box</comment>
|
||||
<translation>Nuova versione</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/autoupdate.cpp" line="431"/>
|
||||
<location filename="../src/autoupdate.cpp" line="458"/>
|
||||
<source>An update is available, do you want to download it now?
|
||||
It will be installed when qTox restarts.</source>
|
||||
<translation>È disponibile una nuova versione di qTox, vuoi scaricarla adesso?
|
||||
|
@ -1372,6 +1377,15 @@ Verrà installata al riavvio del programma.</translation>
|
|||
<comment>Error with the DNS</comment>
|
||||
<translation>La risposta del server DNS non contiene un Tox ID valido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/toxdns.cpp" line="223"/>
|
||||
<location filename="../src/toxdns.cpp" line="267"/>
|
||||
<source>It appears that qTox has to use the old tox1 protocol.
|
||||
Unfortunately tox1 is not secure. Should it be used anyway?</source>
|
||||
<translation>Sembra che qTox debba usare il vecchio protocollo tox1.
|
||||
Sfortunatamente il protocollo tox1 non è sicuro.
|
||||
Usare comunque il protocollo tox1?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ToxURIDialog</name>
|
||||
|
@ -1450,116 +1464,116 @@ Verrà installata al riavvio del programma.</translation>
|
|||
<translation>Occupato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="429"/>
|
||||
<location filename="../src/widget/widget.cpp" line="431"/>
|
||||
<source>Choose a profile</source>
|
||||
<translation>Scegli un profilo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="430"/>
|
||||
<location filename="../src/widget/widget.cpp" line="432"/>
|
||||
<source>Please choose which identity to use</source>
|
||||
<translation>Per favore scegli quale identità usare</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="451"/>
|
||||
<location filename="../src/widget/widget.cpp" line="453"/>
|
||||
<source>Choose a profile picture</source>
|
||||
<translation>Scegli un'immagine per il profilo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="458"/>
|
||||
<location filename="../src/widget/widget.cpp" line="465"/>
|
||||
<location filename="../src/widget/widget.cpp" line="486"/>
|
||||
<location filename="../src/widget/widget.cpp" line="460"/>
|
||||
<location filename="../src/widget/widget.cpp" line="467"/>
|
||||
<location filename="../src/widget/widget.cpp" line="488"/>
|
||||
<source>Error</source>
|
||||
<translation>Errore</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="458"/>
|
||||
<location filename="../src/widget/widget.cpp" line="460"/>
|
||||
<source>Unable to open this file</source>
|
||||
<translation>Impossibile aprire il file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="465"/>
|
||||
<location filename="../src/widget/widget.cpp" line="467"/>
|
||||
<source>Unable to read this image</source>
|
||||
<translation>Impossibile leggere l'immagine</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="486"/>
|
||||
<location filename="../src/widget/widget.cpp" line="488"/>
|
||||
<source>This image is too big</source>
|
||||
<translation>L'immagine è troppo grande</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="526"/>
|
||||
<location filename="../src/widget/widget.cpp" line="528"/>
|
||||
<source>Toxcore failed to start, the application will terminate after you close this message.</source>
|
||||
<translation>Impossibile avviare Toxcore.\nqTox terminerà dopo che avrai chiuso questo messaggio.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="535"/>
|
||||
<location filename="../src/widget/widget.cpp" line="537"/>
|
||||
<source>toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.</source>
|
||||
<comment>popup text</comment>
|
||||
<translation>Impossibile avviare Toxcore con le tue impostazione proxy.\nqTox non può funzionare correttamente, per favore modifica le impostazioni e riavvia il programma.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="574"/>
|
||||
<location filename="../src/widget/widget.cpp" line="576"/>
|
||||
<source>Add friend</source>
|
||||
<translation>Aggiungi contatto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="586"/>
|
||||
<location filename="../src/widget/widget.cpp" line="588"/>
|
||||
<source>File transfers</source>
|
||||
<translation>Files trasferiti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="614"/>
|
||||
<location filename="../src/widget/widget.cpp" line="616"/>
|
||||
<source>Settings</source>
|
||||
<translation>Impostazioni</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="714"/>
|
||||
<location filename="../src/widget/widget.cpp" line="716"/>
|
||||
<source>Couldn't request friendship</source>
|
||||
<translation>Impossibile inviare la richiesta d'amicizia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="742"/>
|
||||
<location filename="../src/widget/widget.cpp" line="744"/>
|
||||
<source>away</source>
|
||||
<comment>contact status</comment>
|
||||
<translation>assente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="744"/>
|
||||
<location filename="../src/widget/widget.cpp" line="746"/>
|
||||
<source>busy</source>
|
||||
<comment>contact status</comment>
|
||||
<translation>occupato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="746"/>
|
||||
<location filename="../src/widget/widget.cpp" line="748"/>
|
||||
<source>offline</source>
|
||||
<comment>contact status</comment>
|
||||
<translation>offline</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="748"/>
|
||||
<location filename="../src/widget/widget.cpp" line="750"/>
|
||||
<source>online</source>
|
||||
<comment>contact status</comment>
|
||||
<translation>online</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="751"/>
|
||||
<location filename="../src/widget/widget.cpp" line="753"/>
|
||||
<source>%1 is now %2</source>
|
||||
<comment>e.g. "Dubslow is now online"</comment>
|
||||
<translation>%1 è ora %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="988"/>
|
||||
<location filename="../src/widget/widget.cpp" line="990"/>
|
||||
<source><Unknown></source>
|
||||
<comment>Placeholder when we don't know someone's name in a group chat</comment>
|
||||
<translation><Sconosciuto></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="1013"/>
|
||||
<location filename="../src/widget/widget.cpp" line="1015"/>
|
||||
<source>%1 has set the title to %2</source>
|
||||
<translation>%1 ha impostato il titolo in %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/widget/widget.cpp" line="1164"/>
|
||||
<location filename="../src/widget/widget.cpp" line="1166"/>
|
||||
<source>Message failed to send</source>
|
||||
<translation>Impossibile inviare il messaggio</translation>
|
||||
</message>
|
||||
|
|
1578
translations/pt.ts
vendored
Normal file
1578
translations/pt.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
422
translations/uk.ts
vendored
422
translations/uk.ts
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user