diff --git a/INSTALL.md b/INSTALL.md index 63cefe8a1..b03f17c7e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -14,6 +14,7 @@ | Tox Core | most recent | core, av | | OpenCV | >= 2.4.9 | core, highgui, imgproc | | OpenAL Soft | >= 1.16.0 | | +| filter_audio | most recent | | @@ -127,6 +128,12 @@ cd /home/user/qTox ./bootstrap.sh # use -h or --help for more information ``` +###filter_audio +You also need to install filter_audio library separately if you did not run ``./bootstrap.sh``. +```bash +./install_libfilteraudio.sh +``` + After all the dependencies are thus reeady to go, compiling should be as simple as ```bash qmake 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/bootstrap.sh b/bootstrap.sh index 3188d9ecc..d705a02c0 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -15,6 +15,7 @@ SODIUM_VER=1.0.0 # directory names of cloned repositories SODIUM_DIR=libsodium-$SODIUM_VER TOX_CORE_DIR=libtoxcore-latest +FILTER_AUDIO_DIR=filter_audio # this boolean describes whether the installation of # libsodium should be skipped or not @@ -42,6 +43,11 @@ if [ -z "$TOX_CORE_DIR" ]; then exit 1 fi +if [ -z "$FILTER_AUDIO_DIR" ]; then + echo "internal error detected!" + echo "FILTER_AUDIO_DIR should not be empty... aborting" + exit 1 +fi ########## check input parameters ########## @@ -95,7 +101,7 @@ mkdir -p ${BASE_DIR} # if exists, otherwise cloning them may fail rm -rf ${BASE_DIR}/${SODIUM_DIR} rm -rf ${BASE_DIR}/${TOX_CORE_DIR} - +rm -rf ${BASE_DIR}/${FILTER_AUDIO_DIR} ############### install step ############### @@ -122,6 +128,12 @@ if [[ $TOX_ONLY = "false" ]]; then fi popd + + if [[ $GLOBAL = "false" ]]; then + ./install_libfilteraudio.sh ${BASE_DIR}/${FILTER_AUDIO_DIR} ${BASE_DIR} + else + ./install_libfilteraudio.sh ${BASE_DIR}/${FILTER_AUDIO_DIR} + fi fi # clone current master of libtoxcore diff --git a/img/taskbar/taskbar_busy.png b/img/taskbar/dark/taskbar_busy.png similarity index 100% rename from img/taskbar/taskbar_busy.png rename to img/taskbar/dark/taskbar_busy.png diff --git a/img/taskbar/taskbar_busy_2x.png b/img/taskbar/dark/taskbar_busy_2x.png similarity index 100% rename from img/taskbar/taskbar_busy_2x.png rename to img/taskbar/dark/taskbar_busy_2x.png diff --git a/img/taskbar/taskbar_idle.png b/img/taskbar/dark/taskbar_idle.png similarity index 100% rename from img/taskbar/taskbar_idle.png rename to img/taskbar/dark/taskbar_idle.png diff --git a/img/taskbar/taskbar_idle_2x.png b/img/taskbar/dark/taskbar_idle_2x.png similarity index 100% rename from img/taskbar/taskbar_idle_2x.png rename to img/taskbar/dark/taskbar_idle_2x.png diff --git a/img/taskbar/taskbar_invisible.png b/img/taskbar/dark/taskbar_invisible.png similarity index 100% rename from img/taskbar/taskbar_invisible.png rename to img/taskbar/dark/taskbar_invisible.png diff --git a/img/taskbar/taskbar_invisible_2x.png b/img/taskbar/dark/taskbar_invisible_2x.png similarity index 100% rename from img/taskbar/taskbar_invisible_2x.png rename to img/taskbar/dark/taskbar_invisible_2x.png diff --git a/img/taskbar/taskbar_offline.png b/img/taskbar/dark/taskbar_offline.png similarity index 100% rename from img/taskbar/taskbar_offline.png rename to img/taskbar/dark/taskbar_offline.png diff --git a/img/taskbar/taskbar_offline_2x.png b/img/taskbar/dark/taskbar_offline_2x.png similarity index 100% rename from img/taskbar/taskbar_offline_2x.png rename to img/taskbar/dark/taskbar_offline_2x.png diff --git a/img/taskbar/taskbar_online.png b/img/taskbar/dark/taskbar_online.png similarity index 100% rename from img/taskbar/taskbar_online.png rename to img/taskbar/dark/taskbar_online.png diff --git a/img/taskbar/taskbar_online_2x.png b/img/taskbar/dark/taskbar_online_2x.png similarity index 100% rename from img/taskbar/taskbar_online_2x.png rename to img/taskbar/dark/taskbar_online_2x.png diff --git a/img/taskbar/light/taskbar_busy.png b/img/taskbar/light/taskbar_busy.png new file mode 100644 index 000000000..6408db92a Binary files /dev/null and b/img/taskbar/light/taskbar_busy.png differ diff --git a/img/taskbar/light/taskbar_busy_2x.png b/img/taskbar/light/taskbar_busy_2x.png new file mode 100644 index 000000000..248e05860 Binary files /dev/null and b/img/taskbar/light/taskbar_busy_2x.png differ diff --git a/img/taskbar/light/taskbar_idle.png b/img/taskbar/light/taskbar_idle.png new file mode 100644 index 000000000..fae60333e Binary files /dev/null and b/img/taskbar/light/taskbar_idle.png differ diff --git a/img/taskbar/light/taskbar_idle_2x.png b/img/taskbar/light/taskbar_idle_2x.png new file mode 100644 index 000000000..93b33eba4 Binary files /dev/null and b/img/taskbar/light/taskbar_idle_2x.png differ diff --git a/img/taskbar/light/taskbar_invisible.png b/img/taskbar/light/taskbar_invisible.png new file mode 100644 index 000000000..cc45ab1f4 Binary files /dev/null and b/img/taskbar/light/taskbar_invisible.png differ diff --git a/img/taskbar/light/taskbar_invisible_2x.png b/img/taskbar/light/taskbar_invisible_2x.png new file mode 100644 index 000000000..19a736b3b Binary files /dev/null and b/img/taskbar/light/taskbar_invisible_2x.png differ diff --git a/img/taskbar/light/taskbar_offline.png b/img/taskbar/light/taskbar_offline.png new file mode 100644 index 000000000..61c18265e Binary files /dev/null and b/img/taskbar/light/taskbar_offline.png differ diff --git a/img/taskbar/light/taskbar_offline_2x.png b/img/taskbar/light/taskbar_offline_2x.png new file mode 100644 index 000000000..db79070bb Binary files /dev/null and b/img/taskbar/light/taskbar_offline_2x.png differ diff --git a/img/taskbar/light/taskbar_online.png b/img/taskbar/light/taskbar_online.png new file mode 100644 index 000000000..007f0d1c9 Binary files /dev/null and b/img/taskbar/light/taskbar_online.png differ diff --git a/img/taskbar/light/taskbar_online_2x.png b/img/taskbar/light/taskbar_online_2x.png new file mode 100644 index 000000000..247e2b217 Binary files /dev/null and b/img/taskbar/light/taskbar_online_2x.png differ diff --git a/install_libfilteraudio.sh b/install_libfilteraudio.sh new file mode 100755 index 000000000..010bcbbac --- /dev/null +++ b/install_libfilteraudio.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +if [ -z $1 ]; then + SOURCE_DIR="filter_audio/" +else + SOURCE_DIR="$1/" +fi + +if [ -z "$2" ]; then + LIB_DIR="/usr/local/lib/" + INCLUDE_DIR="/usr/local/include/" +else + LIB_DIR="$2/lib/" + INCLUDE_DIR="$2/include/" +fi + +echo "Cloning filter_audio from GitHub.com" +git clone https://github.com/irungentoo/filter_audio.git $SOURCE_DIR + +echo "Compiling filter_audio" +cd $SOURCE_DIR +gcc -c -fPIC filter_audio.c aec/*.c agc/*.c ns/*.c other/*.c -lm -lpthread + +echo "Creating shared object file" +gcc *.o -shared -o libfilteraudio.so + +echo "Cleaning up" +rm *.o + +muhcmd="cp libfilteraudio.so $LIB_DIR" +[ -z "$2" ] && muhcmd="sudo $muhcmd" +echo "Installing libfilteraudio.so with $muhcmd" +$muhcmd + +muhcmd="cp *.h $INCLUDE_DIR" +[ -z "$2" ] && muhcmd="sudo $muhcmd" +echo "Installing include files with $muhcmd" +$muhcmd + +echo "Finished." diff --git a/osx/updater.go b/osx/updater.go deleted file mode 100644 index 45232536f..000000000 --- a/osx/updater.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "os/exec" - "os/user" -) - -func fs_type(path string) int { - //name := "FileOrDir" - f, err := os.Open(path) - if err != nil { - fmt.Println(err) - return -1 - } - defer f.Close() - fi, err := f.Stat() - if err != nil { - fmt.Println(err) - return -1 - } - switch mode := fi.Mode(); { - case mode.IsDir(): - return 0 - case mode.IsRegular(): - return 1 - } - - return -1 -} - -func main() { - usr, e := user.Current() - if e != nil { - log.Fatal(e) - } - - update_dir := usr.HomeDir + "/Library/Preferences/tox/update/" - if _, err := os.Stat(update_dir); os.IsNotExist(err) { - fmt.Println("Error: No update folder, is check for updates enabled?") - return - } - fmt.Println("qTox Updater") - - files, _ := ioutil.ReadDir(update_dir) - killqtox := exec.Command("/usr/bin/killall", "qtox") - _ = killqtox.Run() - - for _, file := range files { - if fs_type(update_dir+file.Name()) == 1 { - fmt.Print("Installing: ") - fmt.Println("/Applications/qtox.app/Contents/" + file.Name()) - if _, err := os.Stat("/Applications/qtox.app/Contents/" + file.Name()); os.IsNotExist(err) { - newfile := exec.Command("/usr/libexec/authopen", "-c", "-x", "-m", "drwxrwxr-x+", "/Applications/qtox.app/Contents/"+file.Name()) - newfile.Run() - } - - cat := exec.Command("/bin/cat", update_dir+file.Name()) - auth := exec.Command("/usr/libexec/authopen", "-w", "/Applications/qtox.app/Contents/"+file.Name()) - auth.Stdin, _ = cat.StdoutPipe() - auth.Stdout = os.Stdout - auth.Stderr = os.Stderr - _ = auth.Start() - _ = cat.Run() - _ = auth.Wait() - - } else { - files, _ := ioutil.ReadDir(update_dir + file.Name()) - for _, file2 := range files { - fmt.Print("Installing: ") - fmt.Println("/Applications/qtox.app/Contents/" + file.Name() + "/" + file2.Name()) - - if _, err := os.Stat("/Applications/qtox.app/Contents/" + file.Name() + "/" + file2.Name()); os.IsNotExist(err) { - newfile := exec.Command("/usr/libexec/authopen", "-c", "-x", "-m", "drwxrwxr-x+", "/Applications/qtox.app/Contents/"+file.Name()+"/"+file2.Name()) - newfile.Run() - } - - cat := exec.Command("/bin/cat", update_dir+file.Name()+"/"+file2.Name()) - auth := exec.Command("/usr/libexec/authopen", "-w", "/Applications/qtox.app/Contents/"+file.Name()+"/"+file2.Name()) - auth.Stdin, _ = cat.StdoutPipe() - auth.Stdout = os.Stdout - auth.Stderr = os.Stderr - _ = auth.Start() - _ = cat.Run() - _ = auth.Wait() - } - } - - } - os.RemoveAll(update_dir) - fmt.Println("Update metadata wiped, launching qTox") - launchqtox := exec.Command("/usr/bin/open", "-b", "im.tox.qtox") - launchqtox.Run() -} diff --git a/osx/updater/.gitignore b/osx/updater/.gitignore new file mode 100644 index 000000000..836562412 --- /dev/null +++ b/osx/updater/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/osx/updater/README.md b/osx/updater/README.md new file mode 100644 index 000000000..66d65555f --- /dev/null +++ b/osx/updater/README.md @@ -0,0 +1,13 @@ +The qTox OS X updater is a mix of objective C and Go compiled as static binaries used do effortless updates in the background. + +It uses Objective C to access Apples own security framework and call some long dead APIs in order to give the statically linked go updater permissions to install the latest build without prompting the user for every file. + +* Release commits: ``https://github.com/Tox/qTox_updater`` +* Development commits: ``https://github.mit.edu/sean-2/updater`` + +Compiling: + +* ```clang qtox_sudo.m -framework corefoundation -framework security -framework cocoa -Os -o qtox_sudo``` +* ```go build updater.go``` + +(Starting with this commit all commits will be signed with [this key](http://pgp.mit.edu/pks/lookup?op=get&search=0x13D2043169D25DF4).) diff --git a/osx/updater/qtox_sudo.m b/osx/updater/qtox_sudo.m new file mode 100644 index 000000000..f9de6bcc0 --- /dev/null +++ b/osx/updater/qtox_sudo.m @@ -0,0 +1,273 @@ +// Modifications listed here GPLv3: https://gist.githubusercontent.com/stqism/2e82352026915f8f6ab3/raw/fca6f6f16fb8d61a64b6053dacf50c3433c2e0af/gistfile1.txt +// +// Copyright 2009 Performant Design, LLC. All rights reserved. +// Copyright (C) 2014 Tox Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +// + +#import + +#include +#include +#include +#include + +char *addFileToPath(const char *path, const char *filename) { + char *outbuf; + char *lc; + + lc = (char *)path + strlen(path) - 1; + + if (lc < path || *lc != '/') { + lc = NULL; + } + + while (*filename == '/') { + filename++; + } + + outbuf = malloc(strlen(path) + strlen(filename) + 1 + (lc == NULL ? 1 : 0)); + + sprintf(outbuf, "%s%s%s", path, (lc == NULL) ? "/" : "", filename); + + return outbuf; +} + +int isExecFile(const char *name) { + struct stat s; + + return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode)); +} + +char *which(const char *filename) +{ + char *path, *p, *n; + + path = getenv("PATH"); + + if (!path) { + return NULL; + } + + p = path = strdup(path); + + while (p) { + n = strchr(p, ':'); + + if (n) { + *n++ = '\0'; + } + + if (*p != '\0') { + p = addFileToPath(p, filename); + + if (isExecFile(p)) { + free(path); + + return p; + } + + free(p); + } + + p = n; + } + + free(path); + + return NULL; +} + +int cocoaSudo(char *executable, char *commandArgs[], char *icon, char *prompt) { + int retVal = 1; + OSStatus status; + AuthorizationRef authRef; + + AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0}; + AuthorizationRights rightSet = {1, &right}; + + AuthorizationEnvironment myAuthorizationEnvironment; + AuthorizationItem kAuthEnv[2]; + myAuthorizationEnvironment.items = kAuthEnv; + + AuthorizationFlags flags = kAuthorizationFlagDefaults; + + + if (prompt && icon) { + kAuthEnv[0].name = kAuthorizationEnvironmentPrompt; + kAuthEnv[0].valueLength = strlen(prompt); + kAuthEnv[0].value = prompt; + kAuthEnv[0].flags = 0; + + kAuthEnv[1].name = kAuthorizationEnvironmentIcon; + kAuthEnv[1].valueLength = strlen(icon); + kAuthEnv[1].value = icon; + kAuthEnv[1].flags = 0; + + myAuthorizationEnvironment.count = 2; + } + else if (prompt) { + kAuthEnv[0].name = kAuthorizationEnvironmentPrompt; + kAuthEnv[0].valueLength = strlen(prompt); + kAuthEnv[0].value = prompt; + kAuthEnv[0].flags = 0; + + myAuthorizationEnvironment.count = 1; + } + else if (icon) { + kAuthEnv[0].name = kAuthorizationEnvironmentIcon; + kAuthEnv[0].valueLength = strlen(icon); + kAuthEnv[0].value = icon; + kAuthEnv[0].flags = 0; + + myAuthorizationEnvironment.count = 1; + } + else { + myAuthorizationEnvironment.count = 0; + } + + status = AuthorizationCreate(NULL, &myAuthorizationEnvironment, flags, &authRef); + + if (status != errAuthorizationSuccess) { + NSLog(@"Could not create authorization reference object."); + status = errAuthorizationBadAddress; + } + else { + flags = kAuthorizationFlagDefaults | + kAuthorizationFlagInteractionAllowed | + kAuthorizationFlagPreAuthorize | + kAuthorizationFlagExtendRights; + + status = AuthorizationCopyRights(authRef, &rightSet, &myAuthorizationEnvironment, flags, NULL); + } + + if (status == errAuthorizationSuccess) { + FILE *ioPipe; + char buffer[1024]; + int bytesRead; + + flags = kAuthorizationFlagDefaults; + status = AuthorizationExecuteWithPrivileges(authRef, executable, flags, commandArgs, &ioPipe); + + /* Just pipe processes' stdout to our stdout for now; hopefully can add stdin pipe later as well */ + + for (;;) { + bytesRead = fread(buffer, sizeof(char), 1024, ioPipe); + + if (bytesRead < 1) { + break; + } + + write(STDOUT_FILENO, buffer, bytesRead * sizeof(char)); + } + + pid_t pid; + int pidStatus; + + do { + pid = wait(&pidStatus); + } + while (pid != -1); + + if (status == errAuthorizationSuccess) { + retVal = 0; + } + } + else { + AuthorizationFree(authRef, kAuthorizationFlagDestroyRights); + authRef = NULL; + + if (status != errAuthorizationCanceled) { + // pre-auth failed + NSLog(@"Pre-auth failed"); + } + } + + return retVal; +} + +void usage(char *appNameFull) { + char *appName = strrchr(appNameFull, '/'); + + if (appName == NULL) { + appName = appNameFull; + } + else { + appName++; + } + + fprintf(stderr, "usage: %s command\n", appName); +} + +int main(int argc, char *argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + int retVal = 1; + int programArgsStartAt = 1; + char *icon = NULL; + char *prompt = NULL; + + if (programArgsStartAt >= argc) { + usage(argv[0]); + } + else { + char *executable; + + if (strchr(argv[programArgsStartAt], '/')) { + executable = isExecFile(argv[programArgsStartAt]) ? strdup(argv[programArgsStartAt]) : NULL; + } + else { + executable = which(argv[programArgsStartAt]); + } + + if (executable) { + char **commandArgs = malloc((argc - programArgsStartAt) * sizeof(char**)); + + memcpy(commandArgs, argv + programArgsStartAt + 1, (argc - programArgsStartAt - 1) * sizeof(char**)); + + commandArgs[argc - programArgsStartAt - 1] = NULL; + + retVal = cocoaSudo(executable, commandArgs, icon, prompt); + + free(commandArgs); + free(executable); + } + else { + fprintf(stderr, "Unable to find %s\n", argv[programArgsStartAt]); + + usage(argv[0]); + } + } + + if (prompt) { + free(prompt); + } + + [pool release]; + + return retVal; +} diff --git a/osx/updater/updater.go b/osx/updater/updater.go new file mode 100644 index 000000000..ae7b898d6 --- /dev/null +++ b/osx/updater/updater.go @@ -0,0 +1,133 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "os/user" + "syscall" + + "bitbucket.org/kardianos/osext" +) + +var custom_user string + +func fs_type(path string) int { + //name := "FileOrDir" + f, err := os.Open(path) + if err != nil { + fmt.Println(err) + return -1 + } + defer f.Close() + fi, err := f.Stat() + if err != nil { + fmt.Println(err) + return -1 + } + switch mode := fi.Mode(); { + case mode.IsDir(): + return 0 + case mode.IsRegular(): + return 1 + } + + return -1 +} + +func install(path string, pathlen int) int { + files, _ := ioutil.ReadDir(path) + + for _, file := range files { + if fs_type(path+file.Name()) == 1 { + + addpath := "" + if len(path) != pathlen { + addpath = path[pathlen:len(path)] + } + + fmt.Print("Installing: ") + fmt.Println("/Applications/qtox.app/Contents/" + addpath + file.Name()) + if _, err := os.Stat("/Applications/qtox.app/Contents/" + file.Name()); os.IsNotExist(err) { + newfile := exec.Command("/usr/libexec/authopen", "-c", "-x", "-m", "drwxrwxr-x+", "/Applications/qtox.app/Contents/"+addpath+file.Name()) + newfile.Run() + } + + cat := exec.Command("/bin/cat", path+file.Name()) + + auth := exec.Command("/usr/libexec/authopen", "-w", "/Applications/qtox.app/Contents/"+addpath+file.Name()) + auth.Stdin, _ = cat.StdoutPipe() + auth.Stdout = os.Stdout + auth.Stderr = os.Stderr + _ = auth.Start() + _ = cat.Run() + _ = auth.Wait() + + } else { + install(path+file.Name()+"/", pathlen) + } + } + return 0 +} + +func main() { + syscall.Setuid(0) + usr, e := user.Current() + if e != nil { + log.Fatal(e) + } + +CHECK: + if usr.Name != "System Administrator" { + fmt.Println("Not running as root, relaunching") + + appdir, _ := osext.Executable() + appdir_len := len(appdir) + sudo_path := appdir[0:(appdir_len-7)] + "qtox_sudo" //qtox_sudo is a fork of cocoasudo with all of its flags and other features stripped out + + if _, err := os.Stat(sudo_path); os.IsNotExist(err) { + fmt.Println("Error: No qtox_sudo binary installed, falling back") + custom_user = usr.Name + usr.Name = "System Administrator" + goto CHECK + } + + relaunch := exec.Command(sudo_path, appdir, usr.Name) + relaunch.Stdout = os.Stdout + relaunch.Stderr = os.Stderr + relaunch.Run() + return + + } else { + + if len(os.Args) > 1 || custom_user != "" { + + if custom_user == "" { + custom_user = os.Args[1] + } + + update_dir := "/Users/" + custom_user + "/Library/Preferences/tox/update/" + if _, err := os.Stat(update_dir); os.IsNotExist(err) { + fmt.Println("Error: No update folder, is check for updates enabled?") + return + } + fmt.Println("qTox Updater") + + killqtox := exec.Command("/usr/bin/killall", "qtox") + _ = killqtox.Run() + + install(update_dir, len(update_dir)) + + os.RemoveAll(update_dir) + fmt.Println("Update metadata wiped, launching qTox") + launchqtox := exec.Command("/usr/bin/open", "-b", "im.tox.qtox") + launchqtox.Run() + + } else { + fmt.Println("Error: no user passed") + } + + } +} diff --git a/qtox.pro b/qtox.pro index cbd4f3dc1..2bac68cec 100644 --- a/qtox.pro +++ b/qtox.pro @@ -59,6 +59,12 @@ contains(DISABLE_PLATFORM_EXT, YES) { DEFINES += QTOX_PLATFORM_EXT } +contains(DISABLE_FILTER_AUDIO, YES) { + +} else { + DEFINES += QTOX_FILTER_AUDIO +} + contains(JENKINS,YES) { INCLUDEPATH += ./libs/include/ } else { @@ -71,6 +77,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 @@ -78,6 +92,7 @@ win32 { QMAKE_INFO_PLIST = osx/info.plist LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } + contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } } else { # If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package contains(STATICPKG, YES) { @@ -94,8 +109,16 @@ win32 { LIBS += -lX11 -lXss } + contains(DEFINES, QTOX_FILTER_AUDIO) { + contains(STATICPKG, YES) { + LIBS += -Wl,-Bstatic -lfilteraudio + } else { + LIBS += -lfilteraudio + } + } + contains(JENKINS, YES) { - LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s + LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s } } } @@ -234,6 +257,11 @@ SOURCES += \ src/widget/form/settings/advancedform.cpp \ src/audio.cpp +contains(DEFINES, QTOX_FILTER_AUDIO) { + HEADERS += src/audiofilterer.h + SOURCES += src/audiofilterer.cpp +} + contains(DEFINES, QTOX_PLATFORM_EXT) { HEADERS += src/platform/timer.h SOURCES += src/platform/timer_osx.cpp \ diff --git a/res.qrc b/res.qrc index 40b6d28f2..a62fa5697 100644 --- a/res.qrc +++ b/res.qrc @@ -37,10 +37,14 @@ img/status/dot_online.png img/status/dot_online_2x.png img/status/dot_online_notification.png - img/taskbar/taskbar_online_2x.png - img/taskbar/taskbar_idle_2x.png - img/taskbar/taskbar_busy_2x.png - img/taskbar/taskbar_offline_2x.png + img/taskbar/dark/taskbar_online_2x.png + img/taskbar/dark/taskbar_idle_2x.png + img/taskbar/dark/taskbar_busy_2x.png + img/taskbar/dark/taskbar_offline_2x.png + img/taskbar/light/taskbar_online_2x.png + img/taskbar/light/taskbar_idle_2x.png + img/taskbar/light/taskbar_busy_2x.png + img/taskbar/light/taskbar_offline_2x.png img/transfer.png smileys/cylgom/angel.png smileys/cylgom/angry.png @@ -120,9 +124,11 @@ translations/fi.qm translations/fr.qm translations/it.qm + translations/lt.qm translations/mannol.qm translations/pirate.qm translations/pl.qm + translations/pt.qm translations/ru.qm translations/sv.qm translations/uk.qm diff --git a/res/settings.ini b/res/settings.ini index e335c7c8d..46d3cc207 100644 --- a/res/settings.ini +++ b/res/settings.ini @@ -1,42 +1,86 @@ [DHT%20Server] -dhtServerList\size=9 +dhtServerList\size=21 dhtServerList\1\name=Nikolai Toryzin dhtServerList\1\userId=951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F dhtServerList\1\address=192.254.75.98 dhtServerList\1\port=33445 -dhtServerList\2\name=sonOfRa -dhtServerList\2\userId=04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F -dhtServerList\2\address=144.76.60.215 -dhtServerList\2\port=33445 -dhtServerList\3\name=stal -dhtServerList\3\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074 -dhtServerList\3\address=23.226.230.47 +dhtServerList\2\name=Nikolai Toryzin +dhtServerList\2\userId=2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E +dhtServerList\2\address=31.7.57.236 +dhtServerList\2\port=443 +dhtServerList\3\name=sonOfRa +dhtServerList\3\userId=04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F +dhtServerList\3\address=144.76.60.215 dhtServerList\3\port=33445 -dhtServerList\4\name=aitjcize -dhtServerList\4\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029 -dhtServerList\4\address=54.199.139.199 +dhtServerList\4\name=stal +dhtServerList\4\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074 +dhtServerList\4\address=23.226.230.47 dhtServerList\4\port=33445 dhtServerList\5\name=astonex -dhtServerList\5\userId=B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B -dhtServerList\5\address=37.59.102.176 +dhtServerList\5\userId=10B20C49ACBD968D7C80F2E8438F92EA51F189F4E70CFBBB2C2C8C799E97F03E +dhtServerList\5\address=178.62.125.224 dhtServerList\5\port=33445 -dhtServerList\6\name=nurupo -dhtServerList\6\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67 -dhtServerList\6\address=192.210.149.121 +dhtServerList\6\name=mousey +dhtServerList\6\userId=5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331 +dhtServerList\6\address=37.187.46.132 dhtServerList\6\port=33445 -dhtServerList\7\name=mousey -dhtServerList\7\userId=5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331 -dhtServerList\7\address=37.187.46.132 +dhtServerList\7\name=SylvieLorxu +dhtServerList\7\userId=4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057 +dhtServerList\7\address=178.21.112.187 dhtServerList\7\port=33445 -dhtServerList\8\name=Proplex -dhtServerList\8\userId=7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111 -dhtServerList\8\address=107.161.17.51 +dhtServerList\8\name=Munrek +dhtServerList\8\userId=E398A69646B8CEACA9F0B84F553726C1C49270558C57DF5F3C368F05A7D71354 +dhtServerList\8\address=195.154.119.113 dhtServerList\8\port=33445 -dhtServerList\9\name=SylvieLorxu -dhtServerList\9\userId=4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057 -dhtServerList\9\address=178.21.112.187 +dhtServerList\9\name=nurupo +dhtServerList\9\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67 +dhtServerList\9\address=192.210.149.121 dhtServerList\9\port=33445 -dhtServerList\10\name=Unknown (uTox) -dhtServerList\10\userId=7187969BB10B54C98538BAE94C069CE5C84E650D54F7E596543D8FB1ECF4CF23 -dhtServerList\10\address=95.85.13.245 +dhtServerList\10\name=aitjcize +dhtServerList\10\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029 +dhtServerList\10\address=54.199.139.199 dhtServerList\10\port=33445 +dhtServerList\11\name=Jfreegman +dhtServerList\11\userId=8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C +dhtServerList\11\address=104.219.184.206 +dhtServerList\11\port=443 +dhtServerList\12\name=bunslow +dhtServerList\12\userId=93574A3FAB7D612FEA29FD8D67D3DD10DFD07A075A5D62E8AF3DD9F5D0932E11 +dhtServerList\12\address=76.191.23.96 +dhtServerList\12\port=33445 +dhtServerList\13\name=Martin Schröder +dhtServerList\13\userId=F5A1A38EFB6BD3C2C8AF8B10D85F0F89E931704D349F1D0720C3C4059AF2440A +dhtServerList\13\address=46.38.239.179 +dhtServerList\13\port=33445 +dhtServerList\14\name=lkwg82 +dhtServerList\14\userId=2C308B4518862740AD9A121598BCA7713AFB25858B747313A4D073E2F6AC506C +dhtServerList\14\address=144.76.93.230 +dhtServerList\14\port=33445 +dhtServerList\15\name=Impyy +dhtServerList\15\userId=788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B +dhtServerList\15\address=178.62.250.138 +dhtServerList\15\port=33445 +dhtServerList\16\name=Thierry Thomas +dhtServerList\16\userId=7A2306BFBA665E5480AE59B31E116BE9C04DCEFE04D9FE25082316FA34B4DA0C +dhtServerList\16\address=78.225.128.39 +dhtServerList\16\port=33445 +dhtServerList\17\name=Manolis +dhtServerList\17\userId=461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F +dhtServerList\17\address=130.133.110.14 +dhtServerList\17\port=33445 +dhtServerList\18\name=lawk1 +dhtServerList\18\userId=58D2DE4B169502669941E50780C1630FAA48A0B7026D6F4066C320D47AC6401E +dhtServerList\18\address=178.62.150.106 +dhtServerList\18\port=33445 +dhtServerList\19\name=noisykeyboard +dhtServerList\19\userId=5918AC3C06955962A75AD7DF4F80A5D7C34F7DB9E1498D2E0495DE35B3FE8A57 +dhtServerList\19\address=104.167.101.29 +dhtServerList\19\port=33445 +dhtServerList\20\name=aceawan +dhtServerList\20\userId=391C96CB67AE893D4782B8E4495EB9D89CF1031F48460C06075AA8CE76D50A21 +dhtServerList\20\address=195.154.109.148 +dhtServerList\20\port=33445 +dhtServerList\21\name=pastly +dhtServerList\21\userId=3E1FFDEB667BFF549F619EC6737834762124F50A89C8D0DBF1DDF64A2DD6CD1B +dhtServerList\21\address=192.3.173.88 +dhtServerList\21\port=33445 diff --git a/src/audio.cpp b/src/audio.cpp index a394e72d4..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,20 +258,22 @@ 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); alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued); alSourcei(alSource, AL_LOOPING, AL_FALSE); - if(processed) + if (processed) { ALuint bufids[processed]; alSourceUnqueueBuffers(alSource, processed, bufids); alDeleteBuffers(processed - 1, bufids + 1); bufid = bufids[0]; } - else if(queued < 16) + else if (queued < 16) { alGenBuffers(1, &bufid); } @@ -207,6 +289,30 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u ALint state; alGetSourcei(alSource, AL_SOURCE_STATE, &state); - if(state != AL_PLAYING) + 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/audiofilterer.cpp b/src/audiofilterer.cpp new file mode 100644 index 000000000..2253a6f60 --- /dev/null +++ b/src/audiofilterer.cpp @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + + +#ifdef QTOX_FILTER_AUDIO + +#include "audiofilterer.h" +extern "C"{ +#include +} + +void AudioFilterer::startFilter(unsigned int fs) +{ + closeFilter(); + filter = new_filter_audio(fs); +} + +void AudioFilterer::closeFilter() +{ + if (filter) + kill_filter_audio(filter); + filter = nullptr; +} + + +void AudioFilterer::filterAudio(int16_t* data, int framesize) +{ + if (!filter) + return; + + filter_audio(filter, (int16_t*) data, framesize); +} + + +AudioFilterer::~AudioFilterer() +{ + closeFilter(); +} + +#endif // QTOX_FILTER_AUDIO diff --git a/src/audiofilterer.h b/src/audiofilterer.h new file mode 100644 index 000000000..3a61d4e9f --- /dev/null +++ b/src/audiofilterer.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +#ifdef QTOX_FILTER_AUDIO +#ifndef AUDIOFILTERER_H +#define AUDIOFILTERER_H +#include + +#ifndef _FILTER_AUDIO +typedef struct Filter_Audio Filter_Audio; +#endif + +class AudioFilterer +{ +public: + explicit AudioFilterer() = default; + ~AudioFilterer(); + + void startFilter(unsigned int fs); + void filterAudio(int16_t* data, int framesize); + void closeFilter(); + +private: + struct Filter_Audio* filter{nullptr}; +}; + +#endif // AUDIOFILTERER_H +#endif // QTOX_FILTER_AUDIO 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/core.cpp b/src/core.cpp index 05ce62261..cfdfa422f 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -49,6 +49,8 @@ QList Core::fileRecvQueue; QHash Core::groupCalls; QThread* Core::coreThread{nullptr}; +#define MAX_GROUP_MESSAGE_LEN 1024 + Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) : tox(nullptr), camera(cam), loadPath(loadPath), ready{false} { @@ -121,7 +123,7 @@ void Core::make_tox() // IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options. bool enableIPv6 = Settings::getInstance().getEnableIPv6(); bool forceTCP = Settings::getInstance().getForceTCP(); - bool useProxy = Settings::getInstance().getUseProxy(); + ProxyType proxyType = Settings::getInstance().getProxyType(); if (enableIPv6) qDebug() << "Core starting with IPv6 enabled"; @@ -133,11 +135,11 @@ void Core::make_tox() toxOptions.udp_disabled = forceTCP; // No proxy by default - toxOptions.proxy_enabled = false; + toxOptions.proxy_type = TOX_PROXY_NONE; toxOptions.proxy_address[0] = 0; toxOptions.proxy_port = 0; - if (useProxy) + if (proxyType != ProxyType::ptNone) { QString proxyAddr = Settings::getInstance().getProxyAddr(); int proxyPort = Settings::getInstance().getProxyPort(); @@ -149,7 +151,11 @@ void Core::make_tox() else if (proxyAddr != "" && proxyPort > 0) { qDebug() << "Core: using proxy" << proxyAddr << ":" << proxyPort; - toxOptions.proxy_enabled = true; + // protection against changings in TOX_PROXY_TYPE enum + if (proxyType == ProxyType::ptSOCKS5) + toxOptions.proxy_type = TOX_PROXY_SOCKS5; + else if (proxyType == ProxyType::ptHTTP) + toxOptions.proxy_type = TOX_PROXY_HTTP; uint16_t sz = CString::fromString(proxyAddr, (unsigned char*)toxOptions.proxy_address); toxOptions.proxy_address[sz] = 0; toxOptions.proxy_port = proxyPort; @@ -165,7 +171,7 @@ void Core::make_tox() tox = tox_new(&toxOptions); if (tox == nullptr) { - if (toxOptions.proxy_enabled) + if (toxOptions.proxy_type != TOX_PROXY_NONE) { //QMessageBox::critical(Widget::getInstance(), tr("Proxy failure", "popup title"), //tr("toxcore failed to start with your proxy settings. qTox cannot run; please modify your " @@ -183,7 +189,7 @@ void Core::make_tox() else qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery may not work properly."; } - else if (toxOptions.proxy_enabled) + else if (toxOptions.proxy_type != TOX_PROXY_NONE) { emit badProxy(); return; @@ -728,7 +734,7 @@ void Core::requestFriendship(const QString& friendAddress, const QString& messag { const QString userId = friendAddress.mid(0, TOX_CLIENT_ID_SIZE * 2); - if(hasFriendWithAddress(friendAddress)) + if (hasFriendWithAddress(friendAddress)) { emit failedToAddFriend(userId, QString(tr("Friend is already added"))); } @@ -779,7 +785,7 @@ void Core::sendTyping(int friendId, bool typing) void Core::sendGroupMessage(int groupId, const QString& message) { - QList cMessages = splitMessage(message); + QList cMessages = splitMessage(message, MAX_GROUP_MESSAGE_LEN); for (auto &cMsg :cMessages) { @@ -792,7 +798,7 @@ void Core::sendGroupMessage(int groupId, const QString& message) void Core::sendGroupAction(int groupId, const QString& message) { - QList cMessages = splitMessage(message); + QList cMessages = splitMessage(message, MAX_GROUP_MESSAGE_LEN); for (auto &cMsg :cMessages) { @@ -1677,7 +1683,7 @@ void Core::createGroup(uint8_t type) bool Core::hasFriendWithAddress(const QString &addr) const { // Valid length check - if(addr.length() != (TOX_FRIEND_ADDRESS_SIZE * 2)) + if (addr.length() != (TOX_FRIEND_ADDRESS_SIZE * 2)) { return false; } @@ -1689,7 +1695,7 @@ bool Core::hasFriendWithAddress(const QString &addr) const bool Core::hasFriendWithPublicKey(const QString &pubkey) const { // Valid length check - if(pubkey.length() != (TOX_CLIENT_ID_SIZE * 2)) + if (pubkey.length() != (TOX_CLIENT_ID_SIZE * 2)) { return false; } @@ -1706,7 +1712,7 @@ bool Core::hasFriendWithPublicKey(const QString &pubkey) const QString addrOrId = getFriendAddress(ids[i]); // Set true if found - if(addrOrId.toUpper().startsWith(pubkey.toUpper())) + if (addrOrId.toUpper().startsWith(pubkey.toUpper())) { found = true; break; @@ -1741,17 +1747,17 @@ QString Core::getFriendUsername(int friendnumber) const return CString::toString(name, tox_get_name_size(tox, friendnumber)); } -QList Core::splitMessage(const QString &message) +QList Core::splitMessage(const QString &message, int maxLen) { QList splittedMsgs; QByteArray ba_message(message.toUtf8()); - while (ba_message.size() > TOX_MAX_MESSAGE_LENGTH) + while (ba_message.size() > maxLen) { - int splitPos = ba_message.lastIndexOf(' ', TOX_MAX_MESSAGE_LENGTH - 1); + int splitPos = ba_message.lastIndexOf(' ', maxLen - 1); if (splitPos <= 0) { - splitPos = TOX_MAX_MESSAGE_LENGTH; + splitPos = maxLen; if (ba_message[splitPos] & 0x80) { do { diff --git a/src/core.h b/src/core.h index 2f323bca2..5f55a73cf 100644 --- a/src/core.h +++ b/src/core.h @@ -33,6 +33,9 @@ class QTimer; class QString; class CString; class VideoSource; +#ifdef QTOX_FILTER_AUDIO +class AudioFilterer; +#endif class Core : public QObject { @@ -47,7 +50,7 @@ public: static const QString TOX_EXT; static const QString CONFIG_FILE_NAME; static QString sanitize(QString name); - static QList splitMessage(const QString &message); + static QList splitMessage(const QString &message, int maxLen); QString getPeerName(const ToxID& id) const; @@ -283,6 +286,9 @@ private: int dhtServerId; static QList fileSendQueue, fileRecvQueue; static ToxCall calls[TOXAV_MAX_CALLS]; +#ifdef QTOX_FILTER_AUDIO + static AudioFilterer * filterer[TOXAV_MAX_CALLS]; +#endif static QHash groupCalls; // Maps group IDs to ToxGroupCalls QMutex fileSendMutex, messageSendMutex; bool ready; diff --git a/src/coreav.cpp b/src/coreav.cpp index a00d54ae6..b26be579c 100644 --- a/src/coreav.cpp +++ b/src/coreav.cpp @@ -17,10 +17,17 @@ #include "core.h" #include "video/camera.h" #include "audio.h" +#ifdef QTOX_FILTER_AUDIO +#include "audiofilterer.h" +#endif +#include "misc/settings.h" #include #include ToxCall Core::calls[TOXAV_MAX_CALLS]; +#ifdef QTOX_FILTER_AUDIO +AudioFilterer * Core::filterer[TOXAV_MAX_CALLS] { nullptr}; +#endif const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4}; uint8_t* Core::videobuf; @@ -65,6 +72,19 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled calls[callId].sendVideoTimer->start(); Camera::getInstance()->subscribe(); } + +#ifdef QTOX_FILTER_AUDIO + if (Settings::getInstance().getFilterAudio()) + { + Core::filterer[callId] = new AudioFilterer(); + filterer[callId]->startFilter(48000); + } + else + { + delete filterer[callId]; + filterer[callId] = nullptr; + } +#endif } void Core::onAvMediaChange(void* toxav, int32_t callId, void* core) @@ -194,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) @@ -207,7 +228,7 @@ void Core::playCallAudio(void* toxav, int32_t callId, const int16_t *data, uint1 alGenSources(1, &calls[callId].alSource); ToxAvCSettings dest; - if(toxav_get_peer_csettings((ToxAv*)toxav, callId, 0, &dest) == 0) + if (toxav_get_peer_csettings((ToxAv*)toxav, callId, 0, &dest) == 0) playAudioBuffer(calls[callId].alSource, data, samples, dest.audio_channels, dest.audio_sample_rate); } @@ -216,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; @@ -226,28 +247,25 @@ 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) + if ((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0) { qDebug() << "Core: toxav_prepare_audio_frame error"; calls[callId].sendAudioTimer->start(); return; } - if((r = toxav_send_audio(toxav, callId, dest, r)) < 0) +#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"; + } } calls[callId].sendAudioTimer->start(); } @@ -271,7 +289,7 @@ void Core::sendCallVideo(int callId) if (frame.w && frame.h) { int result; - if((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0) + if ((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0) { qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result); vpx_img_free(&frame); @@ -279,7 +297,7 @@ void Core::sendCallVideo(int callId) return; } - if((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0) + if ((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0) qDebug() << QString("Core: toxav_send_video error: %1").arg(result); vpx_img_free(&frame); @@ -294,14 +312,16 @@ void Core::sendCallVideo(int callId) void Core::micMuteToggle(int callId) { - if (calls[callId].active) { + if (calls[callId].active) + { calls[callId].muteMic = !calls[callId].muteMic; } } void Core::volMuteToggle(int callId) { - if (calls[callId].active) { + if (calls[callId].active) + { calls[callId].muteVol = !calls[callId].muteVol; alSourcef(calls[callId].alSource, AL_GAIN, calls[callId].muteVol ? 0.f : 1.f); } @@ -321,6 +341,15 @@ void Core::onAvCancel(void* _toxav, int32_t callId, void* core) calls[callId].active = false; +#ifdef QTOX_FILTER_AUDIO + if (filterer[callId]) + { + filterer[callId]->closeFilter(); + delete filterer[callId]; + filterer[callId] = nullptr; + } +#endif + emit static_cast(core)->avCancel(friendId, callId); } @@ -379,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); @@ -540,7 +516,7 @@ void Core::onAvStart(void* _toxav, int32_t call_index, void* core) // This function's logic was shamelessly stolen from uTox void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) { - if(!channels || channels > 2) + if (!channels || channels > 2) { qWarning() << "Core::playAudioBuffer: trying to play on "<start(); return; @@ -640,20 +616,10 @@ 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, + if ((r = toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf, framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate)) < 0) { qDebug() << "Core: toxav_group_send_audio error"; 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/main.cpp b/src/main.cpp index 3ecb63d1c..ef378bfbc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) parser.process(a); Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before - if(parser.isSet("P")) + if (parser.isSet("P")) Settings::getInstance().setCurrentProfile(parser.value("P")); sodium_init(); // For the auto-updater @@ -156,7 +156,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } } - else if(!ipc.isCurrentOwner() && !parser.isSet("P")) + else if (!ipc.isCurrentOwner() && !parser.isSet("P")) { time_t event = ipc.postEvent("$activate"); ipc.waitUntilProcessed(event); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 221ef052d..ed58ca986 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1034,7 +1034,7 @@ QSplitter:handle{ 0 0 284 - 401 + 399 @@ -1665,7 +1665,7 @@ QSplitter:handle{ 0 - 57 + 0 @@ -1775,7 +1775,7 @@ QSplitter:handle{ 0 0 775 - 19 + 21 diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp index 3f1635028..87fab140d 100644 --- a/src/misc/settings.cpp +++ b/src/misc/settings.cpp @@ -130,7 +130,7 @@ void Settings::load() autostartInTray = s.value("autostartInTray", false).toBool(); closeToTray = s.value("closeToTray", false).toBool(); forceTCP = s.value("forceTCP", false).toBool(); - useProxy = s.value("useProxy", false).toBool(); + setProxyType(s.value("proxyType", static_cast(ProxyType::ptNone)).toInt()); proxyAddr = s.value("proxyAddr", "").toString(); proxyPort = s.value("proxyPort", 0).toInt(); currentProfile = s.value("currentProfile", "").toString(); @@ -168,6 +168,7 @@ void Settings::load() timestampFormat = s.value("timestampFormat", "hh:mm").toString(); minimizeOnClose = s.value("minimizeOnClose", false).toBool(); minimizeToTray = s.value("minimizeToTray", false).toBool(); + lightTrayIcon = s.value("lightTrayIcon", false).toBool(); useNativeStyle = s.value("nativeStyle", false).toBool(); useEmoticons = s.value("useEmoticons", true).toBool(); statusChangeNotificationEnabled = s.value("statusChangeNotificationEnabled", false).toBool(); @@ -189,7 +190,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(); @@ -198,6 +199,7 @@ void Settings::load() s.beginGroup("Audio"); inDev = s.value("inDev", "").toString(); outDev = s.value("outDev", "").toString(); + filterAudio = s.value("filterAudio", false).toBool(); s.endGroup(); // Read the embedded DHT bootsrap nodes list if needed @@ -281,7 +283,7 @@ void Settings::save(QString path, bool writeFriends) s.setValue("showSystemTray", showSystemTray); s.setValue("autostartInTray",autostartInTray); s.setValue("closeToTray", closeToTray); - s.setValue("useProxy", useProxy); + s.setValue("proxyType", static_cast(proxyType)); s.setValue("forceTCP", forceTCP); s.setValue("proxyAddr", proxyAddr); s.setValue("proxyPort", proxyPort); @@ -317,6 +319,7 @@ void Settings::save(QString path, bool writeFriends) s.setValue("timestampFormat", timestampFormat); s.setValue("minimizeOnClose", minimizeOnClose); s.setValue("minimizeToTray", minimizeToTray); + s.setValue("lightTrayIcon", lightTrayIcon); s.setValue("nativeStyle", useNativeStyle); s.setValue("useEmoticons", useEmoticons); s.setValue("themeColor", themeColor); @@ -340,6 +343,7 @@ void Settings::save(QString path, bool writeFriends) s.beginGroup("Audio"); s.setValue("inDev", inDev); s.setValue("outDev", outDev); + s.setValue("filterAudio", filterAudio); s.endGroup(); if (!writeFriends || currentProfile.isEmpty()) // Core::switchConfiguration @@ -532,6 +536,16 @@ void Settings::setMinimizeToTray(bool newValue) minimizeToTray = newValue; } +bool Settings::getLightTrayIcon() const +{ + return lightTrayIcon; +} + +void Settings::setLightTrayIcon(bool newValue) +{ + lightTrayIcon = newValue; +} + bool Settings::getStatusChangeNotificationEnabled() const { return statusChangeNotificationEnabled; @@ -572,13 +586,17 @@ void Settings::setForceTCP(bool newValue) forceTCP = newValue; } -bool Settings::getUseProxy() const +ProxyType Settings::getProxyType() const { - return useProxy; + return proxyType; } -void Settings::setUseProxy(bool newValue) + +void Settings::setProxyType(int newValue) { - useProxy = newValue; + if (newValue >= 0 && newValue <= 2) + proxyType = static_cast(newValue); + else + proxyType = ProxyType::ptNone; } QString Settings::getProxyAddr() const @@ -888,6 +906,16 @@ void Settings::setOutDev(const QString& deviceSpecifier) outDev = deviceSpecifier; } +bool Settings::getFilterAudio() const +{ + return filterAudio; +} + +void Settings::setFilterAudio(bool newValue) +{ + filterAudio = newValue; +} + QString Settings::getFriendAdress(const QString &publicKey) const { QString key = ToxID::fromString(publicKey).publicKey; diff --git a/src/misc/settings.h b/src/misc/settings.h index 34d495888..3c19f5717 100644 --- a/src/misc/settings.h +++ b/src/misc/settings.h @@ -24,6 +24,8 @@ struct ToxID; namespace Db { enum class syncType; } +enum ProxyType {ptNone, ptSOCKS5, ptHTTP}; + class Settings : public QObject { Q_OBJECT @@ -61,6 +63,9 @@ public: bool getMinimizeToTray() const; void setMinimizeToTray(bool newValue); + + bool getLightTrayIcon() const; + void setLightTrayIcon(bool newValue); QString getStyle() const; void setStyle(const QString& newValue); @@ -86,8 +91,8 @@ public: QString getProxyAddr() const; void setProxyAddr(const QString& newValue); - bool getUseProxy() const; - void setUseProxy(bool newValue); + ProxyType getProxyType() const; + void setProxyType(int newValue); int getProxyPort() const; void setProxyPort(int newValue); @@ -125,6 +130,9 @@ public: QString getOutDev() const; void setOutDev(const QString& deviceSpecifier); + bool getFilterAudio() const; + void setFilterAudio(bool newValue); + // Assume all widgets have unique names // Don't use it to save every single thing you want to save, use it // for some general purpose widgets, such as MainWindows or Splitters, @@ -248,13 +256,14 @@ private: bool autostartInTray; bool closeToTray; bool minimizeToTray; + bool lightTrayIcon; bool useEmoticons; bool checkUpdates; bool showInFront; bool forceTCP; - bool useProxy; + ProxyType proxyType; QString proxyAddr; int proxyPort; @@ -298,6 +307,7 @@ private: // Audio QString inDev; QString outDev; + bool filterAudio; struct friendProp { diff --git a/src/misc/smileypack.cpp b/src/misc/smileypack.cpp index 1ec70f954..c640fffb4 100644 --- a/src/misc/smileypack.cpp +++ b/src/misc/smileypack.cpp @@ -69,9 +69,9 @@ QList > SmileyPack::listSmileyPacks(const QStringList &p if (relPath.leftRef(2) == "..") { - if(!smileyPacks.contains(QPair(packageName, absPath))) + if (!smileyPacks.contains(QPair(packageName, absPath))) smileyPacks << QPair(packageName, absPath); - else if(!smileyPacks.contains(QPair(packageName, relPath))) + else if (!smileyPacks.contains(QPair(packageName, relPath))) smileyPacks << QPair(packageName, relPath); // use relative path for subdirectories } } @@ -97,7 +97,7 @@ bool SmileyPack::load(const QString& filename) // open emoticons.xml QFile xmlFile(filename); - if(!xmlFile.open(QIODevice::ReadOnly)) + if (!xmlFile.open(QIODevice::ReadOnly)) return false; // cannot open file /* parse the cfg file @@ -138,14 +138,14 @@ bool SmileyPack::load(const QString& filename) QPixmap pm; pm.loadFromData(getCachedSmiley(emoticon), "PNG"); - if(pm.size().width() > 0) + if (pm.size().width() > 0) emoticonSet.push_back(emoticon); stringElement = stringElement.nextSibling().toElement(); } - if(emoticonSet.size() > 0) + if (emoticonSet.size() > 0) emoticons.push_back(emoticonSet); } diff --git a/src/platform/timer_win.cpp b/src/platform/timer_win.cpp index e860a5ac6..31542f76f 100644 --- a/src/platform/timer_win.cpp +++ b/src/platform/timer_win.cpp @@ -24,7 +24,7 @@ uint32_t Platform::getIdleTime() { LASTINPUTINFO info = { 0 }; info.cbSize = sizeof(info); - if(GetLastInputInfo(&info)) + if (GetLastInputInfo(&info)) return GetTickCount() - info.dwTime; return 0; } diff --git a/src/platform/timer_x11.cpp b/src/platform/timer_x11.cpp index 5c9ac1b20..263a3b9b6 100644 --- a/src/platform/timer_x11.cpp +++ b/src/platform/timer_x11.cpp @@ -25,7 +25,7 @@ uint32_t Platform::getIdleTime() uint32_t idleTime = 0; Display *display = XOpenDisplay(NULL); - if(!display) + if (!display) { qDebug() << "XOpenDisplay(NULL) failed"; return 0; @@ -33,10 +33,10 @@ uint32_t Platform::getIdleTime() int32_t x11event = 0, x11error = 0; static int32_t hasExtension = XScreenSaverQueryExtension(display, &x11event, &x11error); - if(hasExtension) + if (hasExtension) { XScreenSaverInfo *info = XScreenSaverAllocInfo(); - if(info) + if (info) { XScreenSaverQueryInfo(display, DefaultRootWindow(display), info); idleTime = info->idle; 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/video/cameraworker.cpp b/src/video/cameraworker.cpp index 8671d6568..da98e58f4 100644 --- a/src/video/cameraworker.cpp +++ b/src/video/cameraworker.cpp @@ -129,7 +129,7 @@ void CameraWorker::applyProps() if (!cam.isOpened()) return; - for(int prop : props.keys()) + for (int prop : props.keys()) cam.set(prop, props.value(prop)); } @@ -148,7 +148,7 @@ void CameraWorker::subscribe() void CameraWorker::unsubscribe() { - if(--refCount <= 0) + if (--refCount <= 0) { cam.release(); refCount = 0; diff --git a/src/widget/chatareawidget.cpp b/src/widget/chatareawidget.cpp index 22886ba8c..aeb138014 100644 --- a/src/widget/chatareawidget.cpp +++ b/src/widget/chatareawidget.cpp @@ -65,7 +65,7 @@ void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event) QTextCursor cursor(document()); cursor.setPosition(pos); - if(!cursor.atEnd()) + if (!cursor.atEnd()) { cursor.setPosition(pos+1); diff --git a/src/widget/form/addfriendform.cpp b/src/widget/form/addfriendform.cpp index e0623efa7..efacf17e8 100644 --- a/src/widget/form/addfriendform.cpp +++ b/src/widget/form/addfriendform.cpp @@ -95,7 +95,7 @@ void AddFriendForm::onSendTriggered() this->toxId.clear(); this->message.clear(); } else { - if (Settings::getInstance().getUseProxy()) + if (Settings::getInstance().getProxyType() != ProxyType::ptNone) { QMessageBox::StandardButton btn = QMessageBox::warning(main, "qTox", tr("qTox needs to use the Tox DNS, but can't do it through a proxy.\n\ Ignore the proxy and connect to the Internet directly?"), QMessageBox::Ok|QMessageBox::No, QMessageBox::No); diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 50b455289..b39126be6 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -54,6 +54,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; @@ -71,6 +80,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(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked); @@ -103,7 +113,7 @@ void ChatForm::onSendTriggered() if (isAction) msg = msg = msg.right(msg.length() - 4); - QList splittedMsg = Core::splitMessage(msg); + QList splittedMsg = Core::splitMessage(msg, TOX_MAX_MESSAGE_LENGTH); QDateTime timestamp = QDateTime::currentDateTime(); for (CString& c_msg : splittedMsg) @@ -132,6 +142,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")); @@ -230,10 +255,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(); @@ -267,10 +293,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; @@ -301,11 +328,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; @@ -330,11 +358,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"); @@ -357,10 +385,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(); @@ -386,11 +415,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) @@ -417,11 +446,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"); @@ -446,11 +475,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"); @@ -473,11 +502,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"); @@ -500,11 +529,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"); @@ -529,11 +558,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()); @@ -554,7 +583,7 @@ void ChatForm::onAnswerCallTriggered() } void ChatForm::onHangupCallTriggered() -{ +{ qDebug() << "onHangupCallTriggered"; audioInputFlag = false; @@ -590,11 +619,11 @@ void ChatForm::onVideoCallTriggered() void ChatForm::onAvCallFailed(int FriendId) { - qDebug() << "onAvCallFailed"; - if (FriendId != f->getFriendID()) return; + qDebug() << "onAvCallFailed"; + audioInputFlag = false; audioOutputFlag = false; callButton->disconnect(); @@ -793,7 +822,7 @@ void ChatForm::onLoadHistory() void ChatForm::startCounter() { - if(!timer) + if (!timer) { timer = new QTimer(); connect(timer, SIGNAL(timeout()), this, SLOT(updateTime())); @@ -805,7 +834,7 @@ void ChatForm::startCounter() void ChatForm::stopCounter() { - if(timer) + if (timer) { addSystemInfoMessage(tr("Call with %1 ended. %2").arg(f->getDisplayedName(), secondsToDHMS(timeElapsed.elapsed()/1000)), @@ -834,10 +863,10 @@ QString ChatForm::secondsToDHMS(quint32 duration) int hours = (int) (duration % 24); int days = (int) (duration / 24); - if(minutes == 0) + if (minutes == 0) return cD + res.sprintf("%02ds", seconds); - if(hours == 0 && days == 0) + if (hours == 0 && days == 0) return cD + res.sprintf("%02dm %02ds", minutes, seconds); if (days == 0) @@ -870,6 +899,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 6f6505a8b..a86cf7f81 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(); @@ -100,6 +102,7 @@ private: QLabel *callDuration; QTimer *timer; QElapsedTimer timeElapsed; + QLabel *isTypingLabel; QHash ftransWidgets; void startCounter(); @@ -107,6 +110,7 @@ private: QString secondsToDHMS(quint32 duration); QHash receipts; QMap undeliveredMsgs; + bool isTyping; }; #endif // CHATFORM_H diff --git a/src/widget/form/genericchatform.cpp b/src/widget/form/genericchatform.cpp index 176e3c876..411af8350 100644 --- a/src/widget/form/genericchatform.cpp +++ b/src/widget/form/genericchatform.cpp @@ -52,10 +52,13 @@ GenericChatForm::GenericChatForm(QWidget *parent) : nameLabel->setEditable(true); avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); - QHBoxLayout *headLayout = new QHBoxLayout(), *mainFootLayout = new QHBoxLayout(); - headTextLayout = new QVBoxLayout(); - QVBoxLayout *mainLayout = new QVBoxLayout(); - QVBoxLayout *footButtonsSmall = new QVBoxLayout(), *volMicLayout = new QVBoxLayout(); + QHBoxLayout *headLayout = new QHBoxLayout(), + *mainFootLayout = new QHBoxLayout(); + + QVBoxLayout *mainLayout = new QVBoxLayout(), + *footButtonsSmall = new QVBoxLayout(), + *volMicLayout = new QVBoxLayout(); + headTextLayout = new QVBoxLayout(); chatWidget = new ChatAreaWidget(); @@ -76,10 +79,10 @@ GenericChatForm::GenericChatForm(QWidget *parent) : videoButton->setFixedSize(50,40); videoButton->setToolTip(tr("Video call: RED means you're on a call")); volButton = new QPushButton(); - volButton->setFixedSize(25,20); + //volButton->setFixedSize(25,20); volButton->setToolTip(tr("Toggle speakers volume: RED is OFF")); micButton = new QPushButton(); - micButton->setFixedSize(25,20); + // micButton->setFixedSize(25,20); micButton->setToolTip(tr("Toggle microphone: RED is OFF")); footButtonsSmall->setSpacing(2); @@ -119,6 +122,13 @@ GenericChatForm::GenericChatForm(QWidget *parent) : mainFootLayout->addSpacing(5); mainFootLayout->addWidget(sendButton); mainFootLayout->setSpacing(0); + + headTextLayout->addStretch(); + headTextLayout->addWidget(nameLabel); + + volMicLayout->addWidget(micButton, Qt::AlignTop); + volMicLayout->addSpacing(2); + volMicLayout->addWidget(volButton, Qt::AlignBottom); headWidget->setLayout(headLayout); headLayout->addWidget(avatar); @@ -130,16 +140,6 @@ GenericChatForm::GenericChatForm(QWidget *parent) : headLayout->addWidget(videoButton); headLayout->setSpacing(0); - volMicLayout->addStretch(); - volMicLayout->addSpacing(1); - volMicLayout->addWidget(micButton); - volMicLayout->addSpacing(2); - volMicLayout->addWidget(volButton); - volMicLayout->addStretch(); - - headTextLayout->addStretch(); - headTextLayout->addWidget(nameLabel); - //Fix for incorrect layouts on OS X as per //https://bugreports.qt-project.org/browse/QTBUG-14591 sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); @@ -255,7 +255,8 @@ void GenericChatForm::onEmoteButtonClicked() void GenericChatForm::onChatWidgetClicked() { - msgEdit->setFocus(); + if (!chatWidget->textCursor().hasSelection()) + msgEdit->setFocus(); } void GenericChatForm::onEmoteInsertRequested(QString str) 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/avform.cpp b/src/widget/form/settings/avform.cpp index a506b287a..31f9b6dd9 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -33,12 +33,19 @@ AVForm::AVForm() : bodyUI = new Ui::AVSettings; bodyUI->setupUi(this); +#ifdef QTOX_FILTER_AUDIO + bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio()); +#else + bodyUI->filterAudio->setDisabled(true); +#endif + connect(Camera::getInstance(), &Camera::propProbingFinished, this, &AVForm::onPropProbingFinished); connect(Camera::getInstance(), &Camera::resolutionProbingFinished, this, &AVForm::onResProbingFinished); auto qcomboboxIndexChanged = (void(QComboBox::*)(const QString&)) &QComboBox::currentIndexChanged; connect(bodyUI->inDevCombobox, qcomboboxIndexChanged, this, &AVForm::onInDevChanged); connect(bodyUI->outDevCombobox, qcomboboxIndexChanged, this, &AVForm::onOutDevChanged); + connect(bodyUI->filterAudio, SIGNAL(toggled(bool)), this, SLOT(onFilterAudioToggled(bool))); connect(bodyUI->rescanButton, &QPushButton::clicked, this, [=](){getAudioInDevices(); getAudioOutDevices();}); } @@ -189,3 +196,8 @@ void AVForm::onOutDevChanged(const QString& deviceDescriptor) Settings::getInstance().setOutDev(deviceDescriptor); Audio::openOutput(deviceDescriptor); } + +void AVForm::onFilterAudioToggled(bool filterAudio) +{ + Settings::getInstance().setFilterAudio(filterAudio); +} diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 2d1e873ad..64b34d410 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -52,6 +52,7 @@ private slots: // audio void onInDevChanged(const QString& deviceDescriptor); void onOutDevChanged(const QString& deviceDescriptor); + void onFilterAudioToggled(bool filterAudio); // camera void onPropProbingFinished(Camera::Prop prop, double val); diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index f7e1afc8d..e46c7d43f 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -30,8 +30,8 @@ 0 0 - 810 - 496 + 808 + 618 @@ -96,6 +96,13 @@ + + + + Filter audio + + + diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp index 69b9cb88b..f70704387 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", "lt", "mannol", "pirate", "pl", "pt", "ru", "fi", "sv", "uk"}; +static QStringList langs = {"Български", "Deutsch", "English", "Español", "Français", "Italiano", "Lietuvių", "mannol", "Pirate", "Polski", "Português", "Русский", "Suomi", "Svenska", "Українська"}; static QStringList timeFormats = {"hh:mm AP", "hh:mm", "hh:mm:ss AP", "hh:mm:ss"}; @@ -54,7 +54,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable()); bool showSystemTray = Settings::getInstance().getShowSystemTray(); - + bodyUI->showSystemTray->setChecked(showSystemTray); bodyUI->startInTray->setChecked(Settings::getInstance().getAutostartInTray()); bodyUI->startInTray->setEnabled(showSystemTray); @@ -62,6 +62,8 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : bodyUI->closeToTray->setEnabled(showSystemTray); bodyUI->minimizeToTray->setChecked(Settings::getInstance().getMinimizeToTray()); bodyUI->minimizeToTray->setEnabled(showSystemTray); + bodyUI->lightTrayIcon->setChecked(Settings::getInstance().getLightTrayIcon()); + bodyUI->lightTrayIcon->setEnabled(showSystemTray); bodyUI->statusChanges->setChecked(Settings::getInstance().getStatusChangeNotificationEnabled()); bodyUI->useEmoticons->setChecked(Settings::getInstance().getUseEmoticons()); bodyUI->autoacceptFiles->setChecked(Settings::getInstance().getAutoSaveEnabled()); @@ -80,7 +82,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : bodyUI->styleBrowser->addItem(tr("None")); bodyUI->styleBrowser->addItems(QStyleFactory::keys()); - if(QStyleFactory::keys().contains(Settings::getInstance().getStyle())) + if (QStyleFactory::keys().contains(Settings::getInstance().getStyle())) bodyUI->styleBrowser->setCurrentText(Settings::getInstance().getStyle()); else bodyUI->styleBrowser->setCurrentText(tr("None")); @@ -110,7 +112,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : if (port != -1) bodyUI->proxyPort->setValue(port); - bodyUI->cbUseProxy->setChecked(Settings::getInstance().getUseProxy()); + bodyUI->proxyType->setCurrentIndex(static_cast(Settings::getInstance().getProxyType())); onUseProxyUpdated(); //general @@ -121,11 +123,12 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray); connect(bodyUI->closeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetCloseToTray); connect(bodyUI->minimizeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetMinimizeToTray); + connect(bodyUI->lightTrayIcon, &QCheckBox::stateChanged, this, &GeneralForm::onSetLightTrayIcon); connect(bodyUI->statusChanges, &QCheckBox::stateChanged, this, &GeneralForm::onSetStatusChange); connect(bodyUI->autoAwaySpinBox, SIGNAL(editingFinished()), this, SLOT(onAutoAwayChanged())); connect(bodyUI->showInFront, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowInFront); connect(bodyUI->autoacceptFiles, &QCheckBox::stateChanged, this, &GeneralForm::onAutoAcceptFileChange); - if(bodyUI->autoacceptFiles->isChecked()) + if (bodyUI->autoacceptFiles->isChecked()) connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange())); //theme connect(bodyUI->useEmoticons, &QCheckBox::stateChanged, this, &GeneralForm::onUseEmoticonsChange); @@ -137,7 +140,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : //connection connect(bodyUI->cbEnableIPv6, &QCheckBox::stateChanged, this, &GeneralForm::onEnableIPv6Updated); connect(bodyUI->cbEnableUDP, &QCheckBox::stateChanged, this, &GeneralForm::onUDPUpdated); - connect(bodyUI->cbUseProxy, &QCheckBox::stateChanged, this, &GeneralForm::onUseProxyUpdated); + connect(bodyUI->proxyType, SIGNAL(currentIndexChanged(int)), this, SLOT(onUseProxyUpdated())); connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited); connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int))); connect(bodyUI->reconnectButton, &QPushButton::clicked, this, &GeneralForm::onReconnectClicked); @@ -187,6 +190,12 @@ void GeneralForm::onSetCloseToTray() Settings::getInstance().setCloseToTray(bodyUI->closeToTray->isChecked()); } +void GeneralForm::onSetLightTrayIcon() +{ + Settings::getInstance().setLightTrayIcon(bodyUI->lightTrayIcon->isChecked()); + Widget::getInstance()->updateTrayIcon(); +} + void GeneralForm::onSetMinimizeToTray() { Settings::getInstance().setMinimizeToTray(bodyUI->minimizeToTray->isChecked()); @@ -194,7 +203,7 @@ void GeneralForm::onSetMinimizeToTray() void GeneralForm::onStyleSelected(QString style) { - if(bodyUI->styleBrowser->currentIndex() == 0) + if (bodyUI->styleBrowser->currentIndex() == 0) Settings::getInstance().setStyle("None"); else Settings::getInstance().setStyle(style); @@ -223,7 +232,7 @@ void GeneralForm::onAutoAcceptFileChange() { Settings::getInstance().setAutoSaveEnabled(bodyUI->autoacceptFiles->isChecked()); - if(bodyUI->autoacceptFiles->isChecked() == true) + if (bodyUI->autoacceptFiles->isChecked() == true) connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange())); else disconnect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()),this, SLOT(onAutoSaveDirChange())); @@ -233,7 +242,7 @@ void GeneralForm::onAutoSaveDirChange() { QString previousDir = Settings::getInstance().getGlobalAutoAcceptDir(); QString directory = QFileDialog::getExistingDirectory(0, tr("Choose an auto accept directory","popup title")); - if(directory.isEmpty()) + if (directory.isEmpty()) directory = previousDir; Settings::getInstance().setGlobalAutoAcceptDir(directory); @@ -279,11 +288,11 @@ void GeneralForm::onProxyPortEdited(int port) void GeneralForm::onUseProxyUpdated() { - bool state = bodyUI->cbUseProxy->isChecked(); + int proxytype = bodyUI->proxyType->currentIndex(); - bodyUI->proxyAddr->setEnabled(state); - bodyUI->proxyPort->setEnabled(state); - Settings::getInstance().setUseProxy(state); + bodyUI->proxyAddr->setEnabled(proxytype); + bodyUI->proxyPort->setEnabled(proxytype); + Settings::getInstance().setProxyType(proxytype); } void GeneralForm::onReconnectClicked() @@ -301,7 +310,7 @@ void GeneralForm::reloadSmiles() QStringList smiles; smiles << ":)" << ";)" << ":p" << ":O" << ":["; //just in case... - for(int i = 0; i < emoticons.size(); i++) + for (int i = 0; i < emoticons.size(); i++) smiles.push_front(emoticons.at(i).first()); int pixSize = 30; diff --git a/src/widget/form/settings/generalform.h b/src/widget/form/settings/generalform.h index bd711cfa9..40739b616 100644 --- a/src/widget/form/settings/generalform.h +++ b/src/widget/form/settings/generalform.h @@ -37,6 +37,7 @@ private slots: void onSetShowSystemTray(); void onSetAutostartInTray(); void onSetCloseToTray(); + void onSetLightTrayIcon(); void onSmileyBrowserIndexChanged(int index); void onUDPUpdated(); void onProxyAddrEdited(); diff --git a/src/widget/form/settings/generalsettings.ui b/src/widget/form/settings/generalsettings.ui index a52aa1ffc..dd30309c0 100644 --- a/src/widget/form/settings/generalsettings.ui +++ b/src/widget/form/settings/generalsettings.ui @@ -38,12 +38,12 @@ 0 - 0 - 509 - 849 + -173 + 511 + 797 - + 9 @@ -109,7 +109,7 @@ - + @@ -152,6 +152,13 @@ + + + + Light icon + + + @@ -216,6 +223,9 @@ Set to 0 to disable + + true + minutes @@ -225,9 +235,6 @@ 2147483647 - - true - @@ -294,6 +301,9 @@ + + QFormLayout::AllNonFixedFieldsGrow + 0 @@ -317,23 +327,6 @@ - - - - Style - - - - - - - - 0 - 0 - - - - @@ -391,6 +384,23 @@ + + + + Style + + + + + + + + 0 + 0 + + + + @@ -462,7 +472,7 @@ - + Connection Settings @@ -492,11 +502,40 @@ - - - Use proxy (SOCKS5) - - + + + + + Proxy type + + + + + + + + 0 + 0 + + + + + None + + + + + SOCKS5 + + + + + HTTP + + + + + 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/form/tabcompleter.cpp b/src/widget/form/tabcompleter.cpp index 73d3ffeef..2fbaa48c7 100644 --- a/src/widget/form/tabcompleter.cpp +++ b/src/widget/form/tabcompleter.cpp @@ -52,7 +52,7 @@ void TabCompleter::buildCompletionList() // that section is then used as the completion regex QRegExp regex(QString("^[-_\\[\\]{}|`^.\\\\]*").append(QRegExp::escape(tabAbbrev)), Qt::CaseInsensitive); - for(auto name : group->getPeerList()) + for (auto name : group->getPeerList()) if (regex.indexIn(name) > -1) completionMap[name.toLower()] = name; 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/maskablepixmapwidget.cpp b/src/widget/maskablepixmapwidget.cpp index f0015d6d0..5f8d2ea99 100644 --- a/src/widget/maskablepixmapwidget.cpp +++ b/src/widget/maskablepixmapwidget.cpp @@ -130,6 +130,6 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *) void MaskablePixmapWidget::mousePressEvent(QMouseEvent*) { - if(clickable) + if (clickable) emit clicked(); } diff --git a/src/widget/tool/chatactions/messageaction.cpp b/src/widget/tool/chatactions/messageaction.cpp index 06f27ef1d..93b8271ee 100644 --- a/src/widget/tool/chatactions/messageaction.cpp +++ b/src/widget/tool/chatactions/messageaction.cpp @@ -29,7 +29,7 @@ MessageAction::MessageAction(const QString &author, const QString &message, cons QString MessageAction::getMessage(QString div) { QString message_; - if(Settings::getInstance().getUseEmoticons()) + if (Settings::getInstance().getUseEmoticons()) message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); else message_ = toHtmlChars(message); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index dcf6c67a4..1ee219bb1 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -54,7 +54,7 @@ void toxActivateEventHandler(const QByteArray& data) { - if(data != "$activate") + if (data != "$activate") return; Widget::getInstance()->show(); Widget::getInstance()->activateWindow(); @@ -96,12 +96,11 @@ void Widget::init() statusAway->setIcon(QIcon(":ui/statusButton/dot_idle.png")); connect(statusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); statusBusy = new QAction(tr("Busy"), this); - connect(statusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); statusBusy->setIcon(QIcon(":ui/statusButton/dot_busy.png")); + connect(statusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); actionQuit = new QAction(tr("&Quit"), this); connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); - trayMenu->addAction(new QAction(tr("Change status to:"), this)); trayMenu->addAction(statusOnline); trayMenu->addAction(statusAway); trayMenu->addAction(statusBusy); @@ -116,7 +115,7 @@ void Widget::init() if (Settings::getInstance().getShowSystemTray()){ icon->show(); - if(Settings::getInstance().getAutostartInTray() == false) + if (Settings::getInstance().getAutostartInTray() == false) this->show(); } else @@ -149,7 +148,7 @@ void Widget::init() ui->tooliconsZone->setStyleSheet(Style::resolve("QPushButton{background-color:@themeDark;border:none;}QPushButton:hover{background-color:@themeMediumDark;border:none;}")); - if(QStyleFactory::keys().contains(Settings::getInstance().getStyle()) + if (QStyleFactory::keys().contains(Settings::getInstance().getStyle()) && Settings::getInstance().getStyle() != "None") { ui->mainHead->setStyle(QStyleFactory::create(Settings::getInstance().getStyle())); @@ -243,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))); @@ -300,14 +300,15 @@ void Widget::updateTrayIcon() return; QString status = ui->statusButton->property("status").toString(); QString pic; + QString color = Settings::getInstance().getLightTrayIcon() ? "light" : "dark"; if (status == "online") - pic = ":img/taskbar/taskbar_online_2x.png"; + pic = ":img/taskbar/" + color + "/taskbar_online_2x.png"; else if (status == "away") - pic = ":img/taskbar/taskbar_idle_2x.png"; + pic = ":img/taskbar/" + color + "/taskbar_idle_2x.png"; else if (status == "busy") - pic = ":img/taskbar/taskbar_busy_2x.png"; + pic = ":img/taskbar/" + color + "/taskbar_busy_2x.png"; else - pic = ":img/taskbar/taskbar_offline_2x.png"; + pic = ":img/taskbar/" + color + "/taskbar_offline_2x.png"; icon->setIcon(QIcon(pic)); } @@ -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; @@ -348,7 +350,7 @@ QThread* Widget::getCoreThread() void Widget::closeEvent(QCloseEvent *event) { - if(Settings::getInstance().getShowSystemTray() && Settings::getInstance().getCloseToTray() == true) + if (Settings::getInstance().getShowSystemTray() && Settings::getInstance().getCloseToTray() == true) { event->ignore(); this->hide(); @@ -365,7 +367,7 @@ void Widget::changeEvent(QEvent *event) { if (event->type() == QEvent::WindowStateChange) { - if(isMinimized() && Settings::getInstance().getMinimizeToTray()) + if (isMinimized() && Settings::getInstance().getMinimizeToTray()) { this->hide(); } @@ -415,7 +417,7 @@ QList Widget::searchProfiles() QDir dir(Settings::getSettingsDirPath()); dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); dir.setNameFilters(QStringList("*.tox")); - for(QFileInfo file : dir.entryInfoList()) + for (QFileInfo file : dir.entryInfoList()) out += file.completeBaseName(); return out; } @@ -591,7 +593,7 @@ void Widget::onIconClick(QSystemTrayIcon::ActivationReason reason) { switch (reason) { case QSystemTrayIcon::Trigger: - if(this->isHidden() == true) + if (this->isHidden() == true) { this->show(); this->activateWindow(); @@ -712,7 +714,7 @@ void Widget::addFriend(int friendId, const QString &userId) void Widget::addFriendFailed(const QString&, const QString& errorInfo) { QString info = QString(tr("Couldn't request friendship")); - if(!errorInfo.isEmpty()) { + if (!errorInfo.isEmpty()) { info = info + (QString(": ") + errorInfo); } @@ -725,7 +727,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; @@ -733,7 +735,7 @@ void Widget::onFriendStatusChanged(int friendId, Status status) f->getFriendWidget()->updateStatusLight(); //won't print the message if there were no messages before - if(!f->getChatForm()->isEmpty() + if (!f->getChatForm()->isEmpty() && Settings::getInstance().getStatusChangeNotificationEnabled()) { QString fStatus = ""; @@ -1178,6 +1180,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/de.ts b/translations/de.ts index 6636bf5de..49de50342 100644 --- a/translations/de.ts +++ b/translations/de.ts @@ -4,7 +4,7 @@ AVForm - + Audio/Video Audio/Video @@ -42,32 +42,37 @@ Erneut nach Audiogeräten suchen - + + Filter audio + Audiofilter + + + Video Settings Video Einstellungen - + Resolution Auflösung - + Hue Farbton - + Brightness Helligkeit - + Saturation Sättigung - + Contrast Kontrast @@ -117,8 +122,8 @@ 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 muss Tox DNS nutzen, dies klappt allerdings nicht über einen Proxy. +Ignore the proxy and connect to the Internet directly? + qTox muss das Tox DNS nutzen, dies klappt allerdings nicht über einen Proxy. Soll der Proxy ignoriert und eine direkte Internetverbindung genutzt werden? @@ -127,31 +132,6 @@ Soll der Proxy ignoriert und eine direkte Internetverbindung genutzt werden?DNS error Tox ID existiert nicht - - Error while looking up DNS - The DNS gives the Tox ID associated to toxme.se addresses - Fehler beim Auflösen des DNS - - - Unexpected number of text records - Error with the DNS - Unererwartete Anzahl von Texteinträgen - - - Unexpected number of values in text record - Error with the DNS - Unerwartete Anzahl von Werten innerhalb des Texteintrages - - - The DNS lookup does not contain any Tox ID - Error with the DNS - Der DNS Eintrag enthält keine Tox ID - - - The DNS lookup does not contain a valid Tox ID - Error with the DNS - Der DNS Eintrag enthält keine gültige Tox ID - AdvancedForm @@ -201,18 +181,7 @@ Soll der Proxy ignoriert und eine direkte Internetverbindung genutzt werden? <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> - Synchrones Schreiben in die DB - - - - Camera - - Camera eror - Kamerafehler - - - Camera format %1 not supported, can't use the camera - Kameraformat %1 wird nicht unterstützt. Die Kamera kann nicht verwendet werden + <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Synchrones Schreiben in die DB</span></a></p></body></html> @@ -223,59 +192,65 @@ Soll der Proxy ignoriert und eine direkte Internetverbindung genutzt werden?Historie laden... - + Send a file Datei versenden - + + File not read + Datei nicht gelesen + + + + qTox wasn't able to open %1 + qTox konnte %1 nicht öffnen + + + Bad Idea Schlechte Idee - + You're trying to send a special (sequential) file, that's not going to work! Sie versuchen eine spezielle (sequentielle) Datei zu senden, das funktioniert nicht! - + %1 is calling %1 ruft an - + %1 stopped calling %1 hat den Anruf beendet - + Calling to %1 Rufe %1 an - + Call rejected Anruf abgewiesen - Failed to send file - Fehler beim Senden der Datei + Failed to send file "%1" + Senden der Datei "%1" fehlgeschlagen - + Call with %1 ended. %2 Anruf zu %1 beendet. %2 - + Call duration: Anrufdauer: - - Save chat log - Chatverlauf speichern - ChatTextEdit @@ -285,109 +260,107 @@ Soll der Proxy ignoriert und eine direkte Internetverbindung genutzt werden?Nachricht hier eingeben... - - CopyableElideLabel - - Copy - Kopieren - - Core - + Toxing on qTox Toxen mit qTox - + qTox User qTox Benutzer - + Friend is already added Freund wurde schon hinzugefügt - + Encryption error Verschlüsselungsfehler - + The .tox file is encrypted, but encryption was not checked, continuing regardless. Die .tox Datei ist verschlüsselt, aber die Verschlüsselung wurde nicht geprüft, Vorgang wird trotzdem fortgesetzt. - + Tox datafile decryption password Entschlüsselungspasswort für Tox Datendatei - - - + + + Password error Passwortfehler - - + + Failed to setup password. Empty password. - Fehler beim Setzen des Passwortes. + Setzen des Passwortes fehlgeschlagen. Leeres Passwort. - + Try Again Nochmal versuchen - + Change profile Profil ändern - + Reinit current profile - Aktuelles Profil neu starten + Aktuelles Profil erneut starten - + Wrong password has been entered Es wurde ein falsches Passwort eingegeben - + History Log decryption password Passwort zur Entschlüsselung der Historie - + Encrypted log Verschlüsselte Logdatei - + Your history is encrypted with different password. Do you want to try another password? Ihre Historie wurde mit einem anderen Passwort verschlüsselt. -Wollen Sie ein anderes probieren? +Wollen Sie ein weiteres probieren? - + Due to incorret password history will be disabled. Falsches Passwort, Historie wird deaktiviert. - + + History + Historie + + + NO Password KEIN Passwort - + Will be saved without encryption! Wird ohne Verschlüsselung gespeichert! @@ -395,37 +368,29 @@ Wollen Sie ein anderes probieren? FileTransferInstance - + Save a file Title of the file saving dialog Datei speichern - + Location not writable Title of permissions popup Ort schreibgeschützt - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Sie haben keine Erlaubnis, die Datei in diesen Ort zu speichern. Wählen Sie einen anderen Ort oder beenden Sie den Dialog. - + ETA ETA - - FileTransfertWidget - - Save a file - Title of the file saving dialog - Datei speichern - - FilesForm @@ -456,7 +421,7 @@ Wollen Sie ein anderes probieren? Someone wants to make friends with you - Es hat Ihnen jemand eine Freundschaftsanfrage gesendet + Jemand möchte Ihr Freund werden @@ -513,19 +478,16 @@ Wollen Sie ein anderes probieren? Wähle ein Verzeichnis für die automatische Dateiannahme - + User alias Benutzeralias - - Alias: - Alias: - - - Invite in group - Menu to invite a friend in a groupchat - In Gruppe einladen + + You can also set this by clicking the chat form name. +Alias: + Sie können diesen auch durch Klick auf den Namen des Chatfensters festlegen. +Alias: @@ -542,38 +504,30 @@ Wollen Sie ein anderes probieren? Allgemein - - + + None - Keine + Kein - + Choose an auto accept directory popup title Wählen Sie ein Verzeichnis - + Call active popup title Anwahl aktiviert - + You can't disconnect while a call is active! popup text Abbruch während der Anwahl nicht möglich! - - GeneralPage - - Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 - IPv6 aktivieren (empfohlen) - - GeneralSettings @@ -601,7 +555,7 @@ Wollen Sie ein anderes probieren? Make Tox portable - Mache Tox portabel + Macht Tox portabel @@ -629,143 +583,154 @@ Wollen Sie ein anderes probieren? Ins Tray minimieren - + + Light icon + Helles Icon + + + Show contacts' status changes Zeigt Statusänderungen der Kontakte - + Check for updates on startup (unstable) - Beim Start auf Updates prüfen (nicht stabil) + Prüft beim Start auf Updates (nicht stabil) - + Focus qTox when a message is received Bringt qTox in den Vordergrund, wenn eine Nachricht eintrifft - + Faux offline messaging - + Imitiert Offline Benachrichtigung - + Provided in minutes Angabe in Minuten - + Auto away after (0 to disable) Automatisch abwesend nach (0 deaktiviert) - + Set to 0 to disable Zum Deaktivieren auf 0 setzen - + + You can set this on a per-friend basis by right clicking them. + autoaccept cb tooltip + Sie können dies durch Rechtsklick auf den jeweiligen Freund festlegen. + + + Use emoticons Emoticons benutzen - + Smiley Pack Text on smiley pack label Emoticon Paket - + Style Stil - + Theme color Farbe - + Emoticon size Emoticon Größe - + px Pixel - + Timestamp format Zeitformat - + 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 - Wenn deaktiviert, kann z.B. über Tor getoxt werden. Dies belastet das Tox Netzwerk zusätzlich und sollte nur deaktiviert werden wenn notwendig. + Wenn deaktiviert kann z.B. über Tor getoxt werden. Dies belastet das Tox Netzwerk zusätzlich und sollte nur deaktiviert werden wenn notwendig. - + Enable UDP (recommended) Text on checkbox to disable UDP UDP aktivieren (empfohlen) - + Reconnect reconnect button - Neu verbinden + Erneut verbinden - + minutes Minuten - + Autoaccept files Dateien automatisch annehmen - + Save files in Speichern unter - + PushButton Schaltfläche - + Theme Benutzeroberfläche - + Connection Settings Verbindungseinstellungen - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 IPv6 aktivieren (empfohlen) - + Use proxy (SOCKS5) Proxy benutzen (SOCKS5) - + Address Text on proxy addr label Adresse - + Port Text on proxy port label Port @@ -774,53 +739,53 @@ Wollen Sie ein anderes probieren? GenericChatForm - + Send message Nachricht senden - + Smileys Smileys - + Send file(s) Datei(en) senden - + Audio call: RED means you're on a call Sprachanruf: ROT bedeutet verbunden - + Video call: RED means you're on a call Videoanruf: ROT bedeutet verbunden - + Toggle speakers volume: RED is OFF Schaltet den Lautsprecher ein/aus: ROT ist AUS - + Toggle microphone: RED is OFF Schaltet das Mikrofon ein/aus: ROT ist AUS - - + + Save chat log Chatverlauf speichern - + Clear displayed messages Angezeigte Nachrichten ausblenden - + Cleared Ausgeblendet @@ -828,45 +793,54 @@ Wollen Sie ein anderes probieren? GroupChatForm - + %1 users in chat Number of users in chat %1 Teilnehmer im Chat - - <Unknown> - <Unbekannt> - %1 users in chat %1 Teilnehmer im Chat - - Save chat log - Chatverlauf speichern - GroupWidget - - + + %1 users in chat %1 Teilnehmer im Chat - - + + 0 users in chat kein Teilnehmer im Chat - + + Set title... + Titel festlegen... + + + Quit group Menu to quit a groupchat Gruppe verlassen + + + Group title + Gruppentitel + + + + You can also set this by clicking the chat form name. +Title: + Sie können diesen auch durch Klick auf den Namen des Chatfensters festlegen. +Titel: + IdentityForm @@ -920,7 +894,7 @@ Wollen Sie ein anderes probieren? Failed to remove file - Die Datei konnte nicht entfernt werden + Entfernen der Datei fehlgeschlagen @@ -930,7 +904,7 @@ Wollen Sie ein anderes probieren? Failed to copy file - Die Datei konnte nicht kopiert werden + Kopieren der Datei fehlgeschlagen @@ -953,68 +927,53 @@ Wollen Sie ein anderes probieren? Deletion imminent! deletion confirmation title - Löschen steht an! + Löschen steht bevor! - 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 - Sind Sie sicher, dass dieses Profil gelöscht werden soll? + Wollen Sie dieses Profil wirklich löschen? +Dazugehörige Informationen und Chatprotokolle werden ebenfalls gelöscht. - + Import profile import dialog title Profil importieren - + Tox save file (*.tox) import dialog filter Toxdatei speichern (*.tox) - + Ignoring non-Tox file popup title Keine Toxdatei, wird ignoriert - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Warnung: Sie haben eine Datei gewählt, die keine Toxdatei ist, wird ignoriert. - + Profile already exists import confirm title Profil existiert bereits - + A profile named "%1" already exists. Do you want to erase it? import confirm text Ein Profil mit dem Namen "%1" existiert bereits. Wollen Sie es löschen? - - IdentityPage - - Name - Username/nick - Benutzername - - - Status - Status message - Status - - - Tox ID - Tox ID - - IdentitySettings @@ -1143,17 +1102,17 @@ Wollen Sie ein anderes probieren? Add friends - Freund hinzufügen + Freunde hinzufügen Create a group chat - Gruppenchat erstellen + Gruppenchat anlegen View completed file transfers - Alle Dateiübertragungen anzeigen + Vollendete Dateiübertragungen anzeigen @@ -1165,10 +1124,6 @@ Wollen Sie ein anderes probieren? Close Schließen - - Ctrl+Q - Strg+Q - NetCamView @@ -1202,7 +1157,7 @@ Soll die alte Historiedatei gelöscht werden? PrivacySettings - Typing Notification + Send Typing Notifications Tippen anzeigen @@ -1244,14 +1199,14 @@ Soll die alte Historiedatei gelöscht werden? QObject - + Update The title of a message box Update - - 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. Ein Update steht zur Verfügung, soll es heruntergeladen werden? Es wird beim Neustart von qTox installiert. @@ -1261,6 +1216,16 @@ Es wird beim Neustart von qTox installiert. Tox URI to parse Tox URI parsen + + + Starts new instance and loads specified profile. + Startet eine neue Instanz und lädt das festgelegte Profil. + + + + profile + Profil + Default @@ -1327,14 +1292,6 @@ Es wird beim Neustart von qTox installiert. Lass uns toxen! - - SelfCamView - - Tox video test - Title of the window to test the video/webcam - Tox Video testen - - SetPasswordDialog @@ -1348,34 +1305,6 @@ Es wird beim Neustart von qTox installiert. Passworteingabe wiederholen - - SettingsForm - - User Settings - "Headline" of the window - Einstellungen - - - Name - Username/nick - Benutzername - - - Status - Status message - Status - - - Test video - Text on a button to test the video/webcam - Video testen - - - Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 - IPv6 aktivieren (empfohlen) - - ToxDNS @@ -1438,7 +1367,7 @@ Es wird beim Neustart von qTox installiert. - Do you want to add %1 as a friend ? + Do you want to add %1 as a friend? Wollen Sie %1 als Freund hinzufügen? @@ -1467,181 +1396,161 @@ Es wird beim Neustart von qTox installiert. Widget - Tox - Tox - - - Your name - Ihr Name - - - Your status - Ihr Status - - - Close - Schließen - - - Ctrl+Q - Strg+Q - - - + Online Online - + Away Abwesend - + Busy Beschäftigt - + &Quit &Beenden - + Change status to: - Ändern Sie den Status zu: + Ändert den Status in: - + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Abwesend - + Busy Button to set your status to 'Busy' Beschäftigt - + Choose a profile Wählen Sie ein Profil - + Please choose which identity to use Wählen Sie die Identität, die benutzt werden soll - + Choose a profile picture - Wähle ein Profilbild + Wählen Sie ein Profilbild - - + + Error Fehler - + Unable to open this file Kann diese Datei nicht öffnen - + Unable to read this image Kann dieses Bild nicht einlesen - + This image is too big Dieses Bild ist zu groß - + Toxcore failed to start, the application will terminate after you close this message. Tox startet nicht, die Anwendung wird nach Schließen dieses Fensters beendet. - + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text - Tox startet mit ihren Proxy-Einstellungen nicht. qTox funktioniert nicht, ändern Sie bitte Ihre Einstellungen und starten qTox neu. + Tox startet nicht mit ihren Proxy-Einstellungen. qTox funktioniert nicht, ändern Sie bitte Ihre Einstellungen und starten qTox neu. - + Add friend Freund hinzufügen - + File transfers Dateiübertragungen - + Settings Einstellungen - + Couldn't request friendship Freundschaftsanfrage fehlgeschlagen - + away contact status Abwesend - + busy contact status Beschäftigt - + offline contact status Offline - + online contact status Online - + %1 is now %2 e.g. "Dubslow is now online" %1 ist nun %2 - + <Unknown> Placeholder when we don't know someone's name in a group chat <Unbekannt> - + %1 has set the title to %2 %1 hat den Titel auf %2 gesetzt - + Message failed to send Senden der Nachricht fehlgeschlagen - \ No newline at end of file + diff --git a/translations/fr.ts b/translations/fr.ts index 206cf9356..48cc108ea 100644 --- a/translations/fr.ts +++ b/translations/fr.ts @@ -76,13 +76,13 @@ Add Friends - Ajouter des amis + Ajouter des contacts Tox ID Tox ID of the person you're sending a friend request to - ID Tox + Tox ID @@ -93,25 +93,25 @@ Send friend request - Envoyer la demande d'ami + Envoyer la demande de contact Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! - Je souhaiterais vous ajouter à mes contacts + Je souhaiterais vous ajouter à mes contacts. Please fill in a valid Tox ID Tox ID of the friend you're sending a friend request to - Merci de remplir un ID Tox valide + Merci d'entrer un Tox ID valide You can't add yourself as a friend! When trying to add your own Tox ID as friend - Vous ne pouvez pas vous ajouter vous même en temps qu'ami! + Vous ne pouvez pas vous ajouter vous-même ! @@ -123,19 +123,19 @@ Ignorer le proxy et se connecter directement à Internet ? 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 as besoin d'utiliser le DNS Tox, mais ne peut pas le faire avec un proxy + qTox a besoin d'utiliser le DNS Tox, mais ne peut pas le faire avec un proxy Ignorer le proxy et se connecter directement à Internet ? This Tox ID does not exist DNS error - Cet ID Tox n'existe pas + Ce Tox ID n'existe pas This address does not exist The DNS gives the Tox ID associated to toxme.se addresses - Cette addresse n'existe pas + Cette adresse n'existe pas Error while looking up DNS @@ -178,22 +178,22 @@ Ignorer le proxy et se connecter directement à Internet ? Bad Idea - Mauvaise Idée + Mauvaise idée You're trying to send a special (sequential) file, that's not going to work! - Vous êtes en train d'essayer d'envoyer un fichier spécial (sequentiel), ça ne marchera pas! + Vous êtes en train d'essayer d'envoyer un fichier spécial (sequentiel), ça ne fonctionnera pas ! %1 calling - %1 appelle + %1 appel %1 stopped calling - %1a arreté l'appel + %1 a arreté l'appel @@ -229,7 +229,7 @@ Ignorer le proxy et se connecter directement à Internet ? Toxing on qTox - Toxer avec qTox + Je Tox sur qTox @@ -239,7 +239,7 @@ Ignorer le proxy et se connecter directement à Internet ? Friend is already added - Cet ami est déjà dans cos contact + Ce contact est déjà dans vos contacts @@ -249,7 +249,7 @@ Ignorer le proxy et se connecter directement à Internet ? The .tox file is encrypted, but encryption was not checked, continuing regardless. - Le fichier .tox est chiffré, mais l'encryption n'as pas été activée. Le problème sera ignoré. + Le fichier .tox est chiffré, mais le chiffrement n'a pas été activé. Le problème sera ignoré. @@ -261,14 +261,14 @@ Ignorer le proxy et se connecter directement à Internet ? Password error - Mod de passe invalide + Mot de passe invalide Failed to setup password. Empty password. - Impossible de mettre ne place le mot de passe. + Impossible de mettre en place le mot de passe. Le mot de passe est vide. @@ -289,7 +289,7 @@ Le mot de passe est vide. Wrong password has been entered - Un mauvais mot de passe à été entré + Un mauvais mot de passe a été entré @@ -316,7 +316,7 @@ Voulez-vous essayer un mot de passe différent? Due to incorret password logging will be disabled - À cause d'un mauvais mot de passe, l'historique sera désactivé + Due à l'utilisation d'un mauvais mot de passe, l'historique sera désactivé @@ -326,7 +326,7 @@ Voulez-vous essayer un mot de passe différent? Will be saved without encryption! - L'historique sera sauvegardé sans être chiffré! + L'historique sera sauvegardé sans être chiffré ! @@ -380,12 +380,12 @@ Voulez-vous essayer un mot de passe différent? Friend request Title of the window to aceept/deny a friend request - Demande d'ami + Demande de contact Someone wants to make friends with you - Quelqu'un veut devenir votre ami + Quelqu'un vient de vous ajouter dans sa liste de contacts @@ -395,7 +395,7 @@ Voulez-vous essayer un mot de passe différent? Friend request message: - Message de demande d'ami: + Message au sujet de la demande: @@ -422,7 +422,7 @@ Voulez-vous essayer un mot de passe différent? Copy friend ID Menu to copy the Tox ID of that friend - Copier l'ID ami + Copier l'ID du contact @@ -458,7 +458,7 @@ Voulez-vous essayer un mot de passe différent? Disable global auto accept context menu entry - Désactiver l'acceptation automatique de fichier + Désactiver le téléchargement automatique de fichiers @@ -470,7 +470,7 @@ Voulez-vous essayer un mot de passe différent? Remove friend Menu to remove the friend from our friendlist - Supprimer ami + Supprimer ce contact @@ -502,7 +502,7 @@ Voulez-vous essayer un mot de passe différent? You can't disconnect while a call is active! popup text - Vous ne pouvez pas vous déconnecter avec un appel en cours! + Vous ne pouvez pas vous déconnecter avec un appel en cours ! @@ -520,7 +520,7 @@ Voulez-vous essayer un mot de passe différent? The translation may not load until qTox restarts. - La translation peut ne pas se charger jusqu'à ce que qTox redémarre. + La traduction peut ne pas prendre effet immédiatement. Redémarrez qTox si ce n'est pas le cas. Translation: @@ -550,7 +550,7 @@ Voulez-vous essayer un mot de passe différent? Minimize to tray - Minimizer dans la barre d'état + Minimiser dans la barre d'état @@ -564,7 +564,7 @@ Voulez-vous essayer un mot de passe différent? Auto away after (0 to disable): - Auto-absent après (0 pour désactiver): + Se rendre absent après (0 pour désactiver): @@ -620,7 +620,7 @@ Voulez-vous essayer un mot de passe différent? Reconnect reconnect button - Reconnection + Se reconnecter @@ -640,7 +640,7 @@ Voulez-vous essayer un mot de passe différent? Focus qTox when a message is received - Montrer qTox quand un message est reçu + Montrer la fênetre qTox quand un message est reçu @@ -713,7 +713,7 @@ Voulez-vous essayer un mot de passe différent? This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. force tcp checkbox tooltip - Permet par exemple d'utiliser Tox à travers Tor, mais ce n'est à utiliser que si nécessaire, car cela ralenti le réseau Tox. + Permet par exemple d'utiliser Tox à travers Tor, mais ce n'est à utiliser que si nécessaire car cela ralenti le réseau Tox. Disable UDP (not recommended) @@ -748,7 +748,7 @@ Voulez-vous essayer un mot de passe différent? Smileys - Emoticones + Émoticônes @@ -768,7 +768,7 @@ Voulez-vous essayer un mot de passe différent? Toggle speakers volume - Couper les haut parleurs + Couper les haut-parleurs @@ -818,7 +818,7 @@ Voulez-vous essayer un mot de passe différent? 0 users in chat - 0 personnes + Le groupe est vide @@ -844,7 +844,7 @@ Voulez-vous essayer un mot de passe différent? You can't switch profiles while a call is active! popup text - Vous ne pouvez pas changer de profil quand un appel est en cours! + Vous ne pouvez pas changer de profil quand un appel est en cours ! @@ -894,7 +894,7 @@ Voulez-vous essayer un mot de passe différent? The file you chose could not be written to. - Le fichier que vous avez choisi n'as pas pu être écrit. + Le fichier que vous avez choisi n'es pas disponible en écriture. @@ -912,7 +912,7 @@ Voulez-vous essayer un mot de passe différent? Deletion imminent! deletion confirmation title - Suppression imminente! + Suppression imminente ! @@ -936,13 +936,13 @@ Voulez-vous essayer un mot de passe différent? Ignoring non-Tox file popup title - Fichier non-Tox ignoré + Fichier incompatible avec Tox ignoré Warning: you've chosen a file that is not a Tox save file; ignoring. popup text - Attention: Vous avez sélectionné un fichier qui n'est pas une sauvegarde Tox: il sera ignoré. + Attention: Vous avez sélectionné un fichier qui n'est pas une sauvegarde Tox, il sera ignoré. @@ -986,7 +986,7 @@ Voulez-vous essayer un mot de passe différent? Your Tox ID (click to copy) - Votre ID Tox (cliquez pour copier) + Votre Tox ID (cliquez pour copier) @@ -1033,7 +1033,7 @@ Voulez-vous essayer un mot de passe différent? This is useful to remain safe on public computers delete profile button tooltip - Util pour sécuriser sur un ordinateur public + Utile pour rester en sécurité sur un ordinateur public @@ -1045,7 +1045,7 @@ Voulez-vous essayer un mot de passe différent? New Tox ID new profile button - Nouvel ID Tox + Nouvel Tox ID @@ -1093,12 +1093,12 @@ Voulez-vous essayer un mot de passe différent? Add friends - Ajouter des amis + Ajouter des contacts Create a group chat - Creer un groupe + Créer un groupe @@ -1125,7 +1125,7 @@ Voulez-vous essayer un mot de passe différent? Tox video - Vidéo tox + Vidéo Tox @@ -1145,7 +1145,7 @@ Voulez-vous essayer un mot de passe différent? You already have history log file encrypted with different password Do you want to delete old history file? Vous avez déjà un historique chiffré avec un autre mot de passe -Voulez vous supprimer l'ancien historique? +Voulez vous supprimer l'ancien historique ? @@ -1192,7 +1192,7 @@ Voulez vous supprimer l'ancien historique? Warning: you've chosen a file that is not a Tox save file; ignoring. popup text - Attention: Vous avez sélectionné un fichier qui n'est pas une sauvegarde Tox: il sera ignoré. + Attention: Vous avez sélectionné un fichier qui n'est pas une sauvegarde Tox, il sera ignoré. @@ -1233,12 +1233,12 @@ Voulez vous supprimer l'ancien historique? An update is available, do you want to download it now ? It will be installed when qTox restarts. Une mise à jour est disponible, voulez vous la télécharger maintenant ? -Elle sera installée au prochain démarrage de qTox +Elle sera installée au prochain démarrage de qTox. Tox URI to parse - URI Tox à utiliser + URL Tox à utiliser @@ -1255,7 +1255,7 @@ Elle sera installée au prochain démarrage de qTox Repeat Password - Répetez le mot de passe + Retapez le mot de passe @@ -1270,13 +1270,13 @@ Elle sera installée au prochain démarrage de qTox This address does not exist The DNS gives the Tox ID associated to toxme.se addresses - Cette addresse n'existe pas + Cette adresse n'existe pas Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses - Erreur en consultant le serveur DNS + Une erreur s'est produite en consultant le serveur DNS @@ -1316,22 +1316,22 @@ Elle sera installée au prochain démarrage de qTox Add a friend Title of the window to add a friend through Tox URI - Ajouter un ami + Ajouter un contact Do you want to add %1 as a friend ? - Voulez-vous ajouter %1 à vos amis ? + Voulez-vous ajouter %1 à vos contacts ? User ID: - ID utilisateur: + ID d'utilisateur: Friend request message: - Message de demande d'ami: + Associer un message à cette demande: @@ -1354,7 +1354,7 @@ Elle sera installée au prochain démarrage de qTox away - indisponnible + absent busy @@ -1368,7 +1368,7 @@ Elle sera installée au prochain démarrage de qTox Away - Indisponible + Absent @@ -1383,7 +1383,7 @@ Elle sera installée au prochain démarrage de qTox Change status to: - Changer le status en: + Changer le status par: @@ -1395,7 +1395,7 @@ Elle sera installée au prochain démarrage de qTox Away Button to set your status to 'Away' - Indisponible + Absent @@ -1443,18 +1443,18 @@ Elle sera installée au prochain démarrage de qTox Toxcore failed to start, the application will terminate after you close this message. - Toxcore n'as pas pu démarrer correctement, l'application va quitter quand vous fermerez ce message. + ToxCore n'as pas pu démarrer correctement, l'application va s'arrêter quand vous fermerez cette alerte. toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text - Toxcore n'as pas pu démarrer avec ces paramètres de proxy, qTox ne peut pas continuer; merci de modifier vos paramètres et redémarrer. + ToxCore n'as pas pu démarrer avec ces paramètres proxy. Merci de modifier ou désactiver vos paramètres et redémarrer l'application. Add friend - Ajouter un ami + Ajouter un contact @@ -1469,13 +1469,13 @@ Elle sera installée au prochain démarrage de qTox Couldn't request friendship - Impossible de demander en ami + Impossible d'envoyer la demande de contact away contact status - indisponnible + absent @@ -1487,7 +1487,7 @@ Elle sera installée au prochain démarrage de qTox offline contact status - déconnecté + hors ligne @@ -1510,7 +1510,7 @@ Elle sera installée au prochain démarrage de qTox Message failed to send - Le message n'as pas pu être envoyé + Le message n'as pu être envoyé diff --git a/translations/i18n.pri b/translations/i18n.pri index 668a89f07..d13f328e2 100644 --- a/translations/i18n.pri +++ b/translations/i18n.pri @@ -6,12 +6,14 @@ TRANSLATIONS = translations/es.ts \ translations/fi.ts \ translations/fr.ts \ translations/it.ts \ + translations/lt.ts \ translations/mannol.ts \ translations/pirate.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 87cfae823..116745236 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -12,12 +12,12 @@ AVSettings - + Video Settings Impostazioni Video - + Resolution Risoluzione @@ -52,22 +52,27 @@ Cerca dispositivi audio - + + Filter audio + Filtra audio + + + Hue Colore - + Brightness Luminoistà - + Saturation Saturazione - + Contrast Contrasto @@ -182,62 +187,72 @@ Ignorare le impostazioni del proxy e connettersi direttamente alla rete Tox? ChatForm - + Load History... Carica log... - + Send a file Invia un file - + File not read Impossibile leggere il file - + qTox wasn't able to open %1 qTox non è riuscito ad aprire %1 - + Bad Idea Pessima 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 %1 Stai chiamando %1 - + + Failed to send file "%1" + Invio del file "%1" fallito + + + Call with %1 ended. %2 Chiamata con %1 terminata. %2 - + Call duration: Durata chiamata: - + + is typing... + sta scrivendo... + + + Call rejected Chiamata rifiutata @@ -253,105 +268,105 @@ Ignorare le impostazioni del proxy e connettersi direttamente alla rete Tox? Core - + Toxing on qTox Toxing on qTox - + qTox User qTox User - + Friend is already added Questo contatto è già presente nella tua lista - + Encryption error Errore crittografia - + The .tox file is encrypted, but encryption was not checked, continuing regardless. Il Tox datafile è criptato, ma la crittografia non è abilitata nelle impostazioni. Continuo ignorando le impostazioni. - + Tox datafile decryption password Password per decriptare il Tox datafile - - - + + + Password error Errore password - - + + Failed to setup password. Empty password. Impossibile impostare la password. Password vuota. - + Try Again Riprova - + Change profile Cambia profilo - + Reinit current profile Reinizializza il profilo corrente - + Wrong password has been entered È stata inserita una password sbagliata - + History Log decryption password Password per decriptare i log - + Encrypted log Log criptato - + Your history is encrypted with different password. Do you want to try another password? I log delle chat sono criptati con una password diversa. Vuoi provare ad inserire un'altra password? - + History Chat Log - + Due to incorret password history will be disabled. Password errata, i log delle chat non saranno caricati. - + NO Password Nessuna password - + Will be saved without encryption! Il Tox datafile sarà salvato senza password! @@ -538,17 +553,22 @@ Soprannome: Mostra icona nella traybar - + + Light icon + Icona brillante + + + Set to 0 to disable Imposta 0 per disabilitare - + Connection Settings Impostazioni Connessione - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Abilita IPv6 (consigliato) @@ -590,143 +610,148 @@ Soprannome: Minimizza nella traybar - - Tray icon displays user status - Mostra lo stato nell'icona della traybar - - - - This is a temporary work around until proper systray status icons are available. - Questo è un workaround temporaneo fino a quando non saranno disponibili icone di stato adeguate. - - - + Show contacts' status changes Mostra quando i contatti cambiano stato - + Check for updates on startup (unstable) Controlla aggiornamenti all'avvio (unstable) - + Focus qTox when a message is received Dai il focus a qTox quando arriva un messaggio - + Faux offline messaging Falsi messaggi offline - + Provided in minutes Espresso in minuti - + Auto away after (0 to disable) Imposta assenza dopo - + minutes minuti - + You can set this on a per-friend basis by right clicking them. autoaccept cb tooltip Puoi impostare questa preferenza per ogni singolo contatto usando il click destro sul suo nome. - + Autoaccept files Accetta automaticamente i trasferimenti di files - + Save files in Salva i files in - + PushButton Sfoglia - + Theme Impostazioni Tema - + Use emoticons Usa emoticons - + Smiley Pack Text on smiley pack label Emoticons - + Style Stile - + Theme color Colore - + Emoticon size Dimensione emoticons - + px px - + Timestamp format Formato data/ora - + 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 Disabilitando questo sarà possibile usare qTox con Tor. Tuttavia verrà aggiunto carico alla rete Tox, quindi disabilitare solo se necessario. - + Enable UDP (recommended) Text on checkbox to disable UDP Abilita UDP (consigliato) - - Use proxy (SOCKS5) - Usa proxy (SOCKS5) + + Proxy type + Proxy - + + None + Nessuno + + + + SOCKS5 + SOCKS 5 + + + + HTTP + HTTP + + + Address Text on proxy addr label IP - + Port Text on proxy port label Porta - + Reconnect reconnect button Riconnetti @@ -735,43 +760,43 @@ Soprannome: GenericChatForm - + Send message Invia messaggio - + Smileys Emoticons - + Send file(s) Invia file(s) - + Audio call: RED means you're on a call Chiamata audio: ROSSO significa che la chiamata è in corso - + Video call: RED means you're on a call Videochiamata: ROSSO significa che la chiamata è in corso - + Toggle speakers volume: RED is OFF Imposta volume altoparlanti: ROSSO è SPENTO - + Toggle microphone: RED is OFF Imposta microfono: ROSSO è SPENTO - + Save chat log Salva il log della chat @@ -781,7 +806,7 @@ Soprannome: Rimuovi messaggi visualizzati - + Cleared Pulito @@ -927,42 +952,44 @@ Nome gruppo: - 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 - Sei sicuro di voler eliminare questo profilo? + Sei sicuro di voler eliminare questo profilo? +I contatti e i log delle chat associati ad esso, saranno eliminati. - + Import profile import dialog title Importa profilo - + Tox save file (*.tox) import dialog filter Tox save file (*.tox) - + Ignoring non-Tox file popup title File ignorato - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Attenzione: hai scelto un file che non contiente un profilo Tox.\nQuesto file verrà ignorato. - + Profile already exists import confirm title Profilo già esistente - + A profile named "%1" already exists. Do you want to erase it? import confirm text Un profilo chiamato "%1" esiste già. Vuoi sovrascriverlo? @@ -1151,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 @@ -1233,13 +1260,13 @@ Vuoi eliminare il vecchio file? %1.tox è stato importato con successo - + Update The title of a message box Nuova 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? @@ -1350,6 +1377,15 @@ Verrà installata al riavvio del programma. Error with the DNS La 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 @@ -1409,11 +1445,6 @@ Verrà installata al riavvio del programma. &Quit &Esci - - - Change status to: - Cambia stato in: - Online diff --git a/translations/lt.ts b/translations/lt.ts new file mode 100644 index 000000000..c907a1ae7 --- /dev/null +++ b/translations/lt.ts @@ -0,0 +1,1579 @@ + + + + + AVForm + + + Audio/Video + Garsas ir vaizdas + + + + AVSettings + + + Audio Settings + Garso įrenginiai + + + + Microphone + Įrašymas + + + + Playback + Išvestis + + + + Playback device + Išvesties įrenginys + + + + Capture device + Įrašymo įrenginys + + + + Rescan audio devices + Aptikti garso įrenginius iš naujo + + + + Filter audio + Filtruoti garso signalą + + + + Video Settings + Vaizdo nustatymai + + + + Resolution + Raiška + + + + Hue + Atspalviai + + + + Brightness + Ryškumas + + + + Saturation + Sodrumas + + + + Contrast + Kontrastas + + + + AddFriendForm + + + Add Friends + Pridėti kontaktą + + + + Tox ID + Tox ID of the person you're sending a friend request to + Tox ID + + + + Message + The message you send in friend requests + Prisistatymo žinutė + + + + Send friend request + Siųsti užklausą + + + + Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + Gal susirašinėjam per Tox? + + + + Please fill in a valid Tox ID + Tox ID of the friend you're sending a friend request to + Įveskite tinkamą kontakto Tox ID + + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + Negalite naudoti savo Tox ID! + + + + 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 naudoja Tox DNS, bet tai neįmanoma per įgaliotąjį (proxy) serverį. +Ignoruoti įgaliotąjį serverį ir jungtis prie interneto tiesiogiai? + + + + This Tox ID does not exist + DNS error + Tokio Tox ID nėra + + + + AdvancedForm + + + Advanced + Kita + + + + FULL - very safe, slowest (recommended) + VISADA – saugiai, bet lėtai (rekomenduojama) + + + + NORMAL - almost as safe as FULL, about 20% faster than FULL + ĮPRASTAI – beveik taip pat saugiai, bet 20 % greičiau + + + + OFF - disables all safety, when something goes wrong your history may be lost, fastest (not recommended) + NELAUKTI – apsauga išjungta: kilus problemoms gali dingti pokalbių žurnalas – greičiausia (nerekomenduojama) + + + + AdvancedSettings + + + Form + Forma + + + + <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;">SVARBUS PRANEŠIMAS</span></p><p><span style=" color:#ff0000;">Nebent </span><span style=" font-weight:600; color:#ff0000;">tikrai</span><span style=" color:#ff0000;"> išmanote kaip elgtis, </span><span style=" font-weight:600; color:#ff0000;">nieko</span><span style=" color:#ff0000;"> čia nekeiskite. Pakeitimai gali sukelti problemų naudotis qTox bei net duomenų (pvz., pokalbių žurnalo) praradimą.</span></p></body></html> + + + + Reset to default settings + Atstatyti pradinius nustatymus + + + + History + Pokalbių žurnalas + + + + <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;">Laukti, kol pildoma duomenų bazė</span></a></p></body></html> + + + + ChatForm + + + Load History... + Įkelti pokalbių žurnalą... + + + + Send a file + Siųsti failą + + + + File not read + Failas neperskaitomas + + + + qTox wasn't able to open %1 + qTox nepavyko atidaryti %1 + + + + Bad Idea + Bloga mintis + + + + You're trying to send a special (sequential) file, that's not going to work! + Bandote siųsti ypatingą (nuoseklųjį) failą, tai nepavyks! + + + + %1 is calling + %1 skambina + + + + %1 stopped calling + %1 nutraukė skambutį + + + + Calling to %1 + Skambiname: %1 + + + + Call rejected + Skambutis atmestas + + + + Failed to send file "%1" + Nepavyko nusiųsti failo „%1“ + + + + Call with %1 ended. %2 + Pokalbis su %1 baigėsi. %2 + + + + Call duration: + Pokalbio trukmė: + + + + is typing... + rašo žinutę... + + + + ChatTextEdit + + + Type your message here... + Įveskite čia savo žinutę... + + + + Core + + + Toxing on qTox + Naudoju qTox + + + + qTox User + qTox naudotojas + + + + Friend is already added + Toks kontaktas jau pridėtas + + + + Encryption error + Šifro klaida + + + + The .tox file is encrypted, but encryption was not checked, continuing regardless. + .tox failas užšifruotas: nors šifras nepatikrintas, tęsiame darbą. + + + + Tox datafile decryption password + Slaptažodis Tox duomenų failui iššifruoti + + + + + + Password error + Slaptažodis netinka + + + + + Failed to setup password. +Empty password. + Nepavyko nustatyti slaptažodžio. +Slaptažodis tuščias. + + + + Try Again + Bandykite dar kartą + + + + Change profile + Pakeisti profilį + + + + Reinit current profile + Išvalyti dabartinį profilį + + + + Wrong password has been entered + Įvestas slaptažodis netinka + + + + History Log decryption password + Pokalbių žurnalo šifro slaptažodis + + + + Encrypted log + Žurnalas užšifruotas + + + + Your history is encrypted with different password. +Do you want to try another password? + Jūsų pokalbių žurnalas užšifruotas kitu slaptažodžiu. +Norite išmėginti kitą slaptažodį? + + + + History + Žurnalas + + + + Due to incorret password history will be disabled. + Dėl netinkamo slaptažodžio pokalbių žurnalas išjungtas. + + + + NO Password + NĖRA slaptažodžio + + + + Will be saved without encryption! + Bus saugojama be šifro! + + + + FileTransferInstance + + + Save a file + Title of the file saving dialog + Išsaugoti failą + + + + Location not writable + Title of permissions popup + Įrašyti failo čia neleidžiama + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + Nėra teisių įrašyti failą šioje vietoje. Bandykite įrašyti kitur arba atšaukite dialogo langą. + + + + ETA + Liko + + + + FilesForm + + + Transfered Files + "Headline" of the window + Baigti siųsti failai + + + + Downloads + Parsiųsti + + + + Uploads + Nusiųsti + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + Kontakto užklausa + + + + Someone wants to make friends with you + Kažkas nori su Jumis bendrauti + + + + User ID: + Naudojo ID: + + + + Friend request message: + Prisistatymo žinutė: + + + + Accept + Accept a friend request + Priimti kontaktą + + + + Reject + Reject a friend request + Atmesti kontaktą + + + + FriendWidget + + + Invite to group + Menu to invite a friend to a groupchat + Pakviesti į grupės pokalbį + + + + Copy friend ID + Menu to copy the Tox ID of that friend + Nukopijuoti kontakto ID + + + + Set alias... + Nustatyti slapyvardį... + + + + Auto accept files from this friend + context menu entry + Automatiškai priimti failus iš šio kontakto + + + + Remove friend + Menu to remove the friend from our friendlist + Pašalinti kontaktą + + + + Choose an auto accept directory + popup title + Pasirinkite priimamų failų katalogą + + + + User alias + Naudotojo slapyvardis + + + + You can also set this by clicking the chat form name. +Alias: + Slapyvardį pakeisti galima ir spustelėjus pokalbių lange. +Slapyvardis: + + + + GeneralForm + + + General + Bendrosios + + + + + None + Nėra + + + + Choose an auto accept directory + popup title + Pasirinkite priimamų failų katalogą + + + + Call active + popup title + Vyksta pokalbis + + + + You can't disconnect while a call is active! + popup text + Vykstant pokalbiui atsijungti negalite! + + + + GeneralSettings + + + General Settings + Bendrosios nuostatos + + + + + The translation may not load until qTox restarts. + Vertimas gali nepasirodyti, kol nepaleisite qTox iš naujo. + + + + Translation + Vertimas + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Nuostatas saugoti veikiamajame kataloge, o ne įprastame nuostatų kataloge + + + + Make Tox portable + Leisti persinešti Tox programą + + + + System tray integration + Sistemos juostelės integracija + + + + Show system tray icon + Rodyti sistemos juostelėje + + + + Start in tray + Paleidžiant paslėpti juostelėje + + + + Close to tray + Uždarant paslėpti juostelėje + + + + Minimize to tray + Sumažinant paslėpti juostelėje + + + + Light icon + Šviesi piktograma + + + + Show contacts' status changes + Rodyti kontaktų būsenos pokyčius + + + + Check for updates on startup (unstable) + Ieškoti atnaujinimų paleidžiant (nestabili funkcija) + + + + Focus qTox when a message is received + Sufokusuoti qTox gavus žinutę + + + + Faux offline messaging + Kaupti žinutes atsijungus adresatui + + + + Provided in minutes + Laikas minutėmis + + + + Auto away after (0 to disable) + Automatiškai „pasitraukęs“ po („0“ išjungia) + + + + Set to 0 to disable + Išjungsite nustatydami „0“ + + + + minutes + minučių + + + + You can set this on a per-friend basis by right clicking them. + autoaccept cb tooltip + Galite nustatyti individualiai ant bet kurio kontakto spustelėję dešiniuoju pelės klavišu. + + + + Autoaccept files + Automatiškai priimti failus + + + + Save files in + Išsaugoti failus + + + + PushButton + PushButton + + + + Theme + Apipavidalinimas + + + + Use emoticons + Naudoti jaustukus + + + + Smiley Pack + Text on smiley pack label + Jaustukų rinkinys + + + + Style + Stilius + + + + Theme color + Apipavidalinimo spalva + + + + Emoticon size + Jaustukų dydis + + + + px + px + + + + Timestamp format + Laiko formatas + + + + Connection Settings + Ryšio nuostatos + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Įjungti IPv6 (rekomenduojama) + + + + 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 + Išjungus galima naudotis Tox protokolu per Tor. Tox tinklas dėl to yra papildomai apkraunamas, todėl atžymėkite tik tada, kai reikia. + + + + Enable UDP (recommended) + Text on checkbox to disable UDP + Įjungti UDP (rekomenduojama) + + + + Proxy type + Įgaliotojo serverio tipas + + + + None + Nėra + + + + SOCKS5 + SOCKS5 + + + + HTTP + HTTP + + + + Address + Text on proxy addr label + Adresas + + + + Port + Text on proxy port label + Prievadas + + + + Reconnect + reconnect button + Prisijungti iš naujo + + + + GenericChatForm + + + Send message + Siųsti žinutę + + + + Smileys + Jaustukai + + + + Send file(s) + Siųsti failą (-us) + + + + Audio call: RED means you're on a call + Pokalbis su garsu: RAUDONA reiškia, kad vyksta pokalbis + + + + Video call: RED means you're on a call + Pokalbis su vaizdu: RAUDONA reiškia, kad vyksta pokalbis + + + + Toggle speakers volume: RED is OFF + Garsiakalbiai: RAUDONA reiškia IŠJUNGTA + + + + Toggle microphone: RED is OFF + Mikrofonas: RAUDONA reiškia IŠJUNGTA + + + + + Save chat log + Išsaugoti pokalbio žurnalą + + + + Clear displayed messages + Išvalyti rodomas žinutes + + + + Cleared + Išvalyta + + + + GroupChatForm + + + %1 users in chat + Number of users in chat + Pokalbyje %1 žmonių + + + + %1 users in chat + Pokalbyje %1 žmonių + + + + GroupWidget + + + + %1 users in chat + Pokalbyje %1 žmonių + + + + + 0 users in chat + Pokalbyje žmonių nėra + + + + Set title... + Nustatyti pavadinimą... + + + + Quit group + Menu to quit a groupchat + Palikti grupės pokalbį + + + + Group title + Grupės pavadinimas + + + + You can also set this by clicking the chat form name. +Title: + Pavadinimą pakeisti galima ir spustelėjus pokalbių lange. +Pavadinimas: + + + + IdentityForm + + + Identity + Tapatybė + + + + Call active + popup title + Vyksta pokalbis + + + + You can't switch profiles while a call is active! + popup text + Vykstant pokalbiui profilių keisti negalima! + + + + Rename "%1" + renaming a profile + Pervadinti „%1“ + + + + Profile already exists + rename confirm title + Toks profilis jau yra + + + + A profile named "%1" already exists. Do you want to erase it? + rename confirm text + Profilis „%1“ jau yra. Ar norite jį ištrinti? + + + + Export profile + save dialog title + Eksportuoti profilį + + + + Tox save file (*.tox) + save dialog filter + Tox failas (*.tox) + + + + Failed to remove file + Failo ištrinti nepavyko + + + + The file you chose to overwrite could not be removed first. + Perrašomo failo pirma ištrinti nepavyko. + + + + Failed to copy file + Failo nukopijuoti nepavyko + + + + The file you chose could not be written to. + Nepavyko įrašyti į pasirinktą failą. + + + + Profile currently loaded + current profile deletion warning title + Profilis aktyvus + + + + This profile is currently in use. Please load a different profile before deleting this one. + current profile deletion warning text + Šis profilis yra aktyvus. Prieš jį ištrindami turite įjungti kitą profilį. + + + + Deletion imminent! + deletion confirmation title + Gresia ištrynimas! + + + + Are you sure you want to delete this profile? +Associated friend information and chat logs will be deleted as well. + deletion confirmation text + Ar tikrai norite ištrinti šį profilį? +Susijusi kontaktų informacija bei pokalbių žurnalas bus taip pat ištrinti. + + + + Import profile + import dialog title + Importuoti profilį + + + + Tox save file (*.tox) + import dialog filter + Tox failas (*.tox) + + + + Ignoring non-Tox file + popup title + Rodomi tik Tox failai + + + + Warning: you've chosen a file that is not a Tox save file; ignoring. + popup text + Įspėjimas: pasirinktas failas nėra Tox failas – praleista. + + + + Profile already exists + import confirm title + Toks profilis jau yra + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Profilis „%1“ jau yra. Ar norite jį ištrinti? + + + + IdentitySettings + + + Public Information + Vieša informacija + + + + Name + Vardas + + + + Status + Būsena + + + + Tox ID + Tox ID + + + + Your Tox ID (click to copy) + Jūsų Tox ID (spustelėję nukopijuosite) + + + + Profiles + Profiliai + + + + Available profiles: + Išsaugoti profiliai: + + + + + Switching profiles is disabled during calls + tooltip + Pokalbio metu keisti profilio negalima + + + + Load + load profile button + Aktyvuoti + + + + Rename + rename profile button + Pervadinti + + + + Export + export profile button + Eksportuoti + + + + This is useful to remain safe on public computers + delete profile button tooltip + Tai naudinga, jei norite likti saugūs prie viešai prieinamų kompiuterių + + + + Delete + delete profile button + Ištrinti + + + + Import a profile + import profile button + Importuoti profilį + + + + New Tox ID + new profile button + Naujas Tox ID + + + + InputPasswordDialog + + + Password Dialog + Slaptažodis + + + + Input password: + Įveskite slaptažodį: + + + + LoadHistoryDialog + + + Load History Dialog + Įkelti žurnalą + + + + Load history from: + Įkelti pokalbių žurnalą nuo: + + + + MainWindow + + + Your name + Jūsų vardas + + + + Your status + Jūsų būsena + + + + Add friends + Pridėti kontaktą + + + + Create a group chat + Sukurti grupės pokalbį + + + + View completed file transfers + Rodyti baigtus siųsti failus + + + + Change your settings + Keisti nuostatas + + + + Close + Uždaryti + + + + NetCamView + + + Tox video + Tox vaizdas + + + + PrivacyForm + + + Privacy + Privatumas + + + + Encrypted log + Užšifruotas žurnalas + + + + You already have history log file encrypted with different password +Do you want to delete old history file? + Jau turite kitu slaptažodžiu šifruotą žurnalą +Ar norite senąjį pokalbių žurnalą ištrinti? + + + + PrivacySettings + + + Send Typing Notifications + Rodyti, kad rašote žinutę + + + + Keep History (unstable) + Išsaugoti žurnalą (nestabili funkcija) + + + + Encryption + Šifravimas + + + + Encrypt Tox datafile + Šifruoti Tox duomenų failą + + + + Encrypt History + Šifruoti pokalbių žurnalą + + + + Nospam + Tox ID apsauga nuo nepageidaujamų kontaktų (nospam) + + + + HHHHHHHH + HHHHHHHH + + + + Generate random nospam + Sugeneruoti atsitiktinį + + + + QObject + + + Update + The title of a message box + Atnaujinimas + + + + An update is available, do you want to download it now? +It will be installed when qTox restarts. + Rasta nauja programos versija, ar norite ją parsisiųsti? +Ji bus įdiegta paleidus qTox iš naujo. + + + + Tox URI to parse + analizuoti Tox URI + + + + Starts new instance and loads specified profile. + Atidaro naują langą ir aktyvuoja nurodytą profilį. + + + + profile + profilis + + + + Default + Numatyta + + + + Blue + Mėlyna + + + + Olive + Alyvinė + + + + Red + Raudona + + + + Violet + Violetinė + + + + Ignoring non-Tox file + popup title + Praleidžiamas failas + + + + Warning: you've chosen a file that is not a Tox save file; ignoring. + popup text + Įspėjimas: pasirinktas failas nėra Tox failas – praleista. + + + + Profile already exists + import confirm title + Toks profilis jau yra + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Profilis „%1“ jau yra. Ar norite jį ištrinti? + + + + Profile imported + Profilis importuotas + + + + %1.tox was successfully imported + %1.tox sėkmingai importuotas + + + + Tox me maybe? + Default message in Tox URI friend requests. Write something appropriate! + Gal susirašinėjam per Tox? + + + + SetPasswordDialog + + + Type Password + Įveskite slaptažodį + + + + Repeat Password + Pakartokite slaptažodį + + + + ToxDNS + + + The connection timed out + The DNS gives the Tox ID associated to toxme.se addresses + Ryšio sudaryti nepavyko + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + Tokio adreso nėra + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + Klaida gaunant DNS duomenis + + + + No text record found + Error with the DNS + DNS įrašas nerastas + + + + Unexpected number of values in text record + Error with the DNS + Netinkamas DNS įrašas + + + + The version of Tox DNS used by this server is not supported + Error with the DNS + Šio serverio Tox DNS versija nepalaikoma + + + + The DNS lookup does not contain any Tox ID + Error with the DNS + DNS atsake nėra Tox ID + + + + + The DNS lookup does not contain a valid Tox ID + Error with the DNS + DNS atsake nėra tinkamo Tox ID + + + + + It appears that qTox has to use the old tox1 protocol. +Unfortunately tox1 is not secure. Should it be used anyway? + Panašu, kad qTox turi naudoti senąjį tox1 protokolą. +Deja tox1 protokolas turi saugumo spragų. Tęsti? + + + + ToxURIDialog + + + Add a friend + Title of the window to add a friend through Tox URI + Pridėti kontaktą + + + + Do you want to add %1 as a friend? + Ar norite pridėti %1 į kontaktus? + + + + User ID: + Naudotojo ID: + + + + Friend request message: + Prisistatymo žinutė: + + + + Send + Send a friend request + Siųsti + + + + Cancel + Don't send a friend request + Atšaukti + + + + Widget + + + Online + Prisijungęs + + + + Away + Pasitraukęs + + + + Busy + Užsiėmęs + + + + &Quit + &Baigti + + + + Online + Button to set your status to 'Online' + Prisijungęs + + + + Away + Button to set your status to 'Away' + Pasitraukęs + + + + Busy + Button to set your status to 'Busy' + Užsiėmęs + + + + Choose a profile + Pasirinkti profilį + + + + Please choose which identity to use + Pasirinkite, kurią tapatybę naudoti + + + + Choose a profile picture + Pasirinkite profilio paveikslėlį + + + + + + Error + Klaida + + + + Unable to open this file + Nepavyko atidaryti failo + + + + Unable to read this image + Nepavyko perskaityti paveikslėlio + + + + This image is too big + Paveikslėlis per didelis + + + + Toxcore failed to start, the application will terminate after you close this message. + Toxcore paleisti nepavyko: programa išsijungs uždarius šį pranešimą. + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + Toxcore neprisijungia su Jūsų įgaliotojo serverio nustatymais. qTox negali dirbti – pakeiskite nustatymus ir prisijunkite iš naujo. + + + + Add friend + Pridėti kontaktą + + + + File transfers + Failų siuntimai + + + + Settings + Nuostatos + + + + Couldn't request friendship + Nepavyko nusiųsti užklausos + + + + away + contact status + pasitraukęs (-usi) + + + + busy + contact status + užsiėmęs (-usi) + + + + offline + contact status + neprisijungęs (-usi) + + + + online + contact status + prisijungęs (-usi) + + + + %1 is now %2 + e.g. "Dubslow is now online" + %1 dabar %2 + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Nepažįstamas> + + + + %1 has set the title to %2 + %1 nustatė pavadinimą „%2“ + + + + Message failed to send + Nepavyko nusiųsti žinutės + + + 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/ru.ts b/translations/ru.ts index c7d4fbd76..731d53ce2 100644 --- a/translations/ru.ts +++ b/translations/ru.ts @@ -12,12 +12,12 @@ AVSettings - + Video Settings Настройки видео - + Resolution Разрешение @@ -47,22 +47,32 @@ Устройство записи - + + Rescan audio devices + Повторить поиск аудиоустройств + + + + Filter audio + Фильтрация звука + + + Hue Тон - + Brightness Яркость - + Saturation Насыщенность - + Contrast Контраст @@ -113,8 +123,14 @@ 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, но это нельзя сделать через прокси. +Игнорировать прокси и подлючиться напрямую через интернет? + + + 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 необходимо воспользоваться Tox DNS, но это нельзя сделать через прокси. Игнорировать прокси и подлючиться напрямую через интернет? @@ -152,7 +168,7 @@ Ignore the proxy and connect to the Internet directly ? Form - + Form @@ -183,48 +199,68 @@ Ignore the proxy and connect to the Internet directly ? Загрузить историю... - + 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! ...передаёте последовательный файл и получаете te-le-fun-ken. И переводчик работает по другой линии. По линии «Библиотека». Вы пытаетесь отправить специальный (последовательный) файл. Это так не работает! - - %1 calling + + %1 is calling %1 звонит - + %1 calling + %1 звонит + + + %1 stopped calling %1 прекратил звонить - + Calling to %1 Звоним %1 - + Call rejected Звонок отклонён - + + Failed to send file "%1" + Не удалось отправить файл «%1» + + + Call with %1 ended. %2 Разговор с %1 завершился. %2 - + Call duration: Длительность разговора: @@ -240,106 +276,120 @@ 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 Пароль для расшифровки журнала переписки - + Encrypted log Зашифрованный журнал - + + Your history is encrypted with different password. +Do you want to try another password? + Ваша переписка зашифрована другим паролем. +Ходите попробовать другой пароль? + + + + History + История + + + + Due to incorret password history will be disabled. + Из-за некорректного пароля журналирование будет отключено. + + Your history is encrypted with different password Do you want to try another password? - Ваша переписка зашифрована другим паролем + Ваша переписка зашифрована другим паролем Ходите попробовать другой пароль? - Loggin - Журналирование + Журналирование - Due to incorret password logging will be disabled - Из-за некорректного пароля журналирование будет отключено + Из-за некорректного пароля журналирование будет отключено - + NO Password БЕЗ пароля - + Will be saved without encryption! Будет сохранено без шифрования! @@ -466,14 +516,20 @@ Do you want to try another password? Выбрать папку для автоматического приёма - + User alias Псевдоним пользователя - + + You can also set this by clicking the chat form name. +Alias: + Можно также установить, щёлкнув по имени вверху окна чата. +Псевдоним: + + Alias: - Новый псевдоним: + Новый псевдоним: @@ -484,25 +540,25 @@ Do you want to try another password? Общие - - + + None Отсутствует - + Choose an auto accept directory popup title Выбрать папку для автоматического приёма - + Call active popup title Идёт звонок - + You can't disconnect while a call is active! popup text Нельзя отключиться пока идёт звонок! @@ -522,130 +578,140 @@ Do you want to try another password? Перевод не изменится до перезапуска qTox. - + + System tray integration + Настройки трея + + + Show system tray icon Показывать иконку в трее - + Close to tray Сворачивать в трей при закрытии - + Minimize to 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 — не менять) - + Set to 0 to disable Укажите 0, чтобы отключить - + You can set this on a per-friend basis by right clicking them. autoaccept cb tooltip Можно настроить отдельно для каждого друга (щёлкнув правой кнопкой мыши по другу и выбрав соответствующий пункт меню). - + Use emoticons Использовать смайлики - + Smiley Pack Text on smiley pack label Набор смайликов - + Style Стиль - + Theme color Цвет темы - + Emoticon size Размер смайликов - + px По аналогии с Мпикс. Хотя, может лучше принять http://ilyabirman.ru/meanwhile/all/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 Отключение позволяет, например, использовать Tox поверх Tor. Однако это добавляет нагрузку на сеть Tox, так что отключайте только в случае необходимости. - + Enable UDP (recommended) Text on checkbox to disable UDP Включить UDP (рекомендуется) - + Use proxy (SOCKS5) Использовать прокси (SOCKS5) - + Address Text on proxy addr label Адрес - + Port Text on proxy port label Порт - + Reconnect reconnect button Переподключиться @@ -667,42 +733,42 @@ Do you want to try another password? Портативный режим - + Start in tray Запускать свёрнутым в трей - + Show contacts' status changes Показывать изменения статусов контактов - + Provided in minutes Выставлено в минутах - + minutes минут - + Autoaccept files Автоматически принимать файлы - + Save files in Сохранять в - + PushButton - + Theme Тема @@ -710,53 +776,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 Очищено @@ -764,13 +830,13 @@ Do you want to try another password? GroupChatForm - + %1 users in chat Number of users in chat %1 пользователей в чате - + %1 users in chat %1 пользователей в чате @@ -778,23 +844,40 @@ Do you want to try another password? GroupWidget - + Quit group Menu to quit a groupchat Покинуть группу - - + + %1 users in chat %1 пользователей в чате - - + + 0 users in chat Ни одного пользователя в чате + + + Set title... + Установить заголовок... + + + + Group title + Заголовок группы + + + + You can also set this by clicking the chat form name. +Title: + Можно также установить, щёлкнув по заголовку вверху окна чата. +Заголовок: + IdentityForm @@ -885,42 +968,49 @@ Do you want to try another password? + Are you sure you want to delete this profile? +Associated friend information and chat logs will be deleted as well. + deletion confirmation text + Вы действительно хотите удалить этот профиль? +Связанная с ним информация о друзьях и история переписки будут также удалены. + + Are you sure you want to delete this profile? deletion confirmation text - Вы действительно хотите удалить этот профиль? + Вы действительно хотите удалить этот профиль? - + Import profile import dialog title Импортировать профиль - + Tox save file (*.tox) import dialog filter Файл Tox (*.tox) - + Ignoring non-Tox file popup title Выбран не файл Tox - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Внимание: вы выбрали не файл Tox; игнорирование. - + Profile already exists import confirm title Профиль уже существует - + A profile named "%1" already exists. Do you want to erase it? import confirm text Профиль с именем «%1» уже существует. Перезаписать? @@ -1151,16 +1241,22 @@ Do you want to delete old history file? QObject - + Update The title of a message box Обновление - + + An update is available, do you want to download it now? +It will be installed when qTox restarts. + Обновление доступно, не желаете ли скачать его прямо сейчас? +Оно будет установлено после того, как qTox будет перезапущен. + + An update is available, do you want to download it now ? It will be installed when qTox restarts. - Обновление доступно, не желаете ли скачать его прамо сейчас? + Обновление доступно, не желаете ли скачать его прамо сейчас? Оно будет установлено после того, как qTox будет перезапущен. @@ -1209,6 +1305,18 @@ It will be installed when qTox restarts. Без перевода, так как весь остальной CLI на английском Tox URI to parse + + + Starts new instance and loads specified profile. + Без перевода, так как весь остальной CLI на английском + Starts new instance and loads specified profile. + + + + profile + Без перевода, так как весь остальной CLI на английском + profile + Default @@ -1309,8 +1417,12 @@ It will be installed when qTox restarts. Добавить друга - Do you want to add %1 as a friend ? + Хотите добавить %1 в друзья? + + + + Do you want to add %1 as a friend? Хотите добавить %1 в друзья? @@ -1339,160 +1451,160 @@ It will be installed when qTox restarts. Widget - + Online В сети - + Away Отошёл - + Busy Занят - + &Quit В&ыход - + Change status to: Сменить статус на: - + Online Button to set your status to 'Online' В сети - + Away Button to set your status to 'Away' Вероятно, это не столь долгое путешествие Отошёл - + Busy Button 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. Не удалось запустить toxcore, приложение будет завершено после того как вы закроете это сообщение. - + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text Не удалось запустить toxcore с вашими настройками прокси, qTox не может работать; измените ваши настройки и перезапустите его. - + Add friend Добавить друга - + File transfers Передачи файлов - + Settings Настройки - + Couldn't request friendship Не удалось запросить добавление в друзья - + away contact status отсутствует - + busy contact status занят - + offline contact status офлайн - + online contact status в сети - + %1 is now %2 e.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 Не удалось отправить сообщение 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? - Ваша історія зашифрована інакшим паролем + Ваша історія зашифрована інакшим паролем. Бажаєте спробувати інший пароль? - - Encrypted log - Зашифрований звіт + + History + Історія - - Loggin - Звітування + + Due to incorret password history will be disabled. + Введено некоректний пароль, звітування вимкнено. - - Due to incorret password logging will be disabled - Введено некоректний пароль, звітування вимкнено + + Encrypted log + Зашифрований звіт - + 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 directory popup title Оберіть теку, для автоматичного отримання файлів - + Call active popup title Дзвінок активний - + You can't disconnect while a call is active! popup text Ви не можете від'єднатись під час активного дзвінка! @@ -526,47 +558,52 @@ Do you want to try another password? Портативний запуск - + + 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 Pack Text 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 (рекомендовано) - + + Proxy type + Тип проксі + + + + None + Відсутній + + + + SOCKS5 + SOCKS5 + + + + HTTP + HTTP + + Use proxy (SOCKS5) - Використовувати проксі (SOCKS5) + Використовувати проксі (SOCKS5) - + Address Text on proxy addr label Адреса - + Port Text on proxy port label Порт - + Reconnect reconnect 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 chat Number 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 group Menu 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 profile import dialog title Імпортувати профіль - + Tox save file (*.tox) import dialog filter Файл збереження Tox (*.tox) - + Ignoring non-Tox file popup title Ігнорування не Tox файлу - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Увага: вказаний вами файл не є файлом збереження Tox; ігнорую. - + Profile already exists import 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 успішно імпортовано - + Update The 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 parse Tox 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: - Змінити статус на: + Змінити статус на: - + Online Button to set your status to 'Online' В мережі - + Away Button to set your status to 'Away' Відійшов - + Busy Button 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 Не вдалось надіслати запит на дружбу - + away contact status Відійшов - + busy contact status Зайнятий - + offline contact status Поза мережею - + online contact status В мережі - + %1 is now %2 e.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 Не вдалось відправити повідомлення diff --git a/ui/chatArea/chatHead.css b/ui/chatArea/chatHead.css index b953e86e5..206e09883 100644 --- a/ui/chatArea/chatHead.css +++ b/ui/chatArea/chatHead.css @@ -1,3 +1,9 @@ +QLineEdit { + color: @black; + background: white; + border: 0px; +} + #nameLabel { color: @black; font: @mediumBold; diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index dc1f46d73..286775142 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -34,7 +34,7 @@ div.date_me { } span.quote { - color: #6bc260; + color: #279419; } div.green { @@ -87,3 +87,7 @@ div.button { margin-left: 0px; color: @white; } + +a { + color: blue; +} diff --git a/ui/volButton/volButton.css b/ui/volButton/volButton.css index 3bf4d64a8..8210f4819 100644 --- a/ui/volButton/volButton.css +++ b/ui/volButton/volButton.css @@ -5,7 +5,7 @@ QPushButton#green background-repeat: none; border: none; width: 25px; - height: 20px; + height: 18px; } QPushButton#green:hover @@ -20,7 +20,7 @@ QPushButton#red background-repeat: none; border: none; width: 25px; - height: 20px; + height: 18px; } QPushButton:focus { diff --git a/ui/volButton/volButton.png b/ui/volButton/volButton.png index a1c474eab..b07c13209 100644 Binary files a/ui/volButton/volButton.png and b/ui/volButton/volButton.png differ diff --git a/ui/volButton/volButtonHover.png b/ui/volButton/volButtonHover.png index 82c126c8f..4a5e47d97 100644 Binary files a/ui/volButton/volButtonHover.png and b/ui/volButton/volButtonHover.png differ diff --git a/ui/volButton/volButtonPressed.png b/ui/volButton/volButtonPressed.png index e0078285e..c2379c1c9 100644 Binary files a/ui/volButton/volButtonPressed.png and b/ui/volButton/volButtonPressed.png differ