diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 35ced1e38b..3f60fab73d 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -164,8 +164,6 @@ jobs: # Pre-compile Python bytecode so each pytest worker doesn't need to $PYTEST --collect-only -m 'not slow' -qq && \ MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \ - ./selfdrive/ui/tests/create_test_translations.sh && \ - QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \ chmod -R 777 /tmp/comma_download_cache" process_replay: @@ -242,42 +240,6 @@ jobs: source selfdrive/test/setup_vsound.sh && \ CI=1 pytest -s tools/sim/tests/test_metadrive_bridge.py" - create_ui_report: - # This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml - name: Create UI Report - runs-on: ${{ - (github.repository == 'commaai/openpilot') && - ((github.event_name != 'pull_request') || - (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) - && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') - || fromJSON('["ubuntu-24.04"]') }} - if: false # FIXME: FrameReader is broken on CI runners - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: caching frames - id: frames-cache - uses: actions/cache@v4 - with: - path: .ci_cache/comma_download_cache - key: ui_screenshots_test_${{ hashFiles('selfdrive/ui/tests/test_ui/run.py') }} - - name: Build openpilot - run: ${{ env.RUN }} "scons -j$(nproc)" - - name: Create Test Report - timeout-minutes: ${{ ((steps.frames-cache.outputs.cache-hit == 'true') && 1 || 3) }} - run: > - ${{ env.RUN }} "PYTHONWARNINGS=ignore && - source selfdrive/test/setup_xvfb.sh && - CACHE_ROOT=/tmp/comma_download_cache python3 selfdrive/ui/tests/test_ui/run.py && - chmod -R 777 /tmp/comma_download_cache" - - name: Upload Test Report - uses: actions/upload-artifact@v4 - with: - name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }} - path: selfdrive/ui/tests/test_ui/report_1/screenshots - create_raylib_ui_report: name: Create raylib UI Report runs-on: ${{ diff --git a/.github/workflows/ui_preview.yaml b/.github/workflows/ui_preview.yaml deleted file mode 100644 index 9ec7a59223..0000000000 --- a/.github/workflows/ui_preview.yaml +++ /dev/null @@ -1,174 +0,0 @@ -name: "ui preview" -on: - push: - branches: - - master - pull_request_target: - types: [assigned, opened, synchronize, reopened, edited] - branches: - - 'master' - paths: - - 'selfdrive/ui/**' - workflow_dispatch: - -env: - UI_JOB_NAME: "Create UI Report" - REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }} - SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }} - BRANCH_NAME: "openpilot/pr-${{ github.event.number }}" - -jobs: - preview: - #if: github.repository == 'commaai/openpilot' - if: false # FIXME: FrameReader is broken on CI runners - name: preview - runs-on: ubuntu-latest - timeout-minutes: 20 - permissions: - contents: read - pull-requests: write - actions: read - steps: - - name: Waiting for ui generation to start - run: sleep 30 - - - name: Waiting for ui generation to end - uses: lewagon/wait-on-check-action@v1.3.4 - with: - ref: ${{ env.SHA }} - check-name: ${{ env.UI_JOB_NAME }} - repo-token: ${{ secrets.GITHUB_TOKEN }} - allowed-conclusions: success - wait-interval: 20 - - - name: Getting workflow run ID - id: get_run_id - run: | - echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ env.SHA }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?[0-9]+)") | .number')" >> $GITHUB_OUTPUT - - - name: Getting proposed ui - id: download-artifact - uses: dawidd6/action-download-artifact@v6 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - run_id: ${{ steps.get_run_id.outputs.run_id }} - search_artifacts: true - name: report-1-${{ env.REPORT_NAME }} - path: ${{ github.workspace }}/pr_ui - - - name: Getting master ui - uses: actions/checkout@v4 - with: - repository: commaai/ci-artifacts - ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }} - path: ${{ github.workspace }}/master_ui - ref: openpilot_master_ui - - - name: Saving new master ui - if: github.ref == 'refs/heads/master' && github.event_name == 'push' - working-directory: ${{ github.workspace }}/master_ui - run: | - git checkout --orphan=new_master_ui - git rm -rf * - git branch -D openpilot_master_ui - git branch -m openpilot_master_ui - git config user.name "GitHub Actions Bot" - git config user.email "<>" - mv ${{ github.workspace }}/pr_ui/*.png . - git add . - git commit -m "screenshots for commit ${{ env.SHA }}" - git push origin openpilot_master_ui --force - - - name: Finding diff - if: github.event_name == 'pull_request_target' - id: find_diff - run: >- - sudo apt-get update && sudo apt-get install -y imagemagick - - scenes=$(find ${{ github.workspace }}/pr_ui/*.png -type f -printf "%f\n" | cut -d '.' -f 1 | grep -v 'pair_device') - A=($scenes) - - DIFF="" - TABLE="
All Screenshots" - TABLE="${TABLE}" - - for ((i=0; i<${#A[*]}; i=i+1)); - do - # Check if the master file exists - if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then - # This is a new file in PR UI that doesn't exist in master - DIFF="${DIFF}
" - DIFF="${DIFF}${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$" - DIFF="${DIFF}
" - - DIFF="${DIFF}" - DIFF="${DIFF} " - DIFF="${DIFF}" - - DIFF="${DIFF}
" - DIFF="${DIFF}
" - elif ! compare -fuzz 2% -highlight-color DeepSkyBlue1 -lowlight-color Black -compose Src ${{ github.workspace }}/master_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png; then - convert ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png -transparent black mask.png - composite mask.png ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png - convert -delay 100 ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png -loop 0 ${{ github.workspace }}/pr_ui/${A[$i]}_diff.gif - - mv ${{ github.workspace }}/master_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_master_ref.png - - DIFF="${DIFF}
" - DIFF="${DIFF}${A[$i]} : \$\${\\color{red}\\text{DIFFERENT}}\$\$" - DIFF="${DIFF}" - - DIFF="${DIFF}" - DIFF="${DIFF} " - DIFF="${DIFF} " - DIFF="${DIFF}" - - DIFF="${DIFF}" - DIFF="${DIFF} " - DIFF="${DIFF} " - DIFF="${DIFF}" - - DIFF="${DIFF}
master proposed
diff composite diff
" - DIFF="${DIFF}
" - else - rm -f ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png - fi - - INDEX=$(($i % 2)) - if [[ $INDEX -eq 0 ]]; then - TABLE="${TABLE}" - fi - TABLE="${TABLE} " - if [[ $INDEX -eq 1 || $(($i + 1)) -eq ${#A[*]} ]]; then - TABLE="${TABLE}" - fi - done - - TABLE="${TABLE}" - - echo "DIFF=$DIFF$TABLE" >> "$GITHUB_OUTPUT" - - - name: Saving proposed ui - if: github.event_name == 'pull_request_target' - working-directory: ${{ github.workspace }}/master_ui - run: | - git config user.name "GitHub Actions Bot" - git config user.email "<>" - git checkout --orphan=${{ env.BRANCH_NAME }} - git rm -rf * - mv ${{ github.workspace }}/pr_ui/* . - git add . - git commit -m "screenshots for PR #${{ github.event.number }}" - git push origin ${{ env.BRANCH_NAME }} --force - - - name: Comment Screenshots on PR - if: github.event_name == 'pull_request_target' - uses: thollander/actions-comment-pull-request@v2 - with: - message: | - - ## UI Preview - ${{ steps.find_diff.outputs.DIFF }} - comment_tag: run_id_screenshots - pr_number: ${{ github.event.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index d3306a11ba..b700df0c88 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,6 @@ a.out *.class *.pyxbldc *.vcd -*.qm *.mo *_pyx.cpp config.json diff --git a/SConstruct b/SConstruct index 80273db106..648afdae57 100644 --- a/SConstruct +++ b/SConstruct @@ -165,57 +165,7 @@ else: np_version = SCons.Script.Value(np.__version__) Export('envCython', 'np_version') -# ********** Qt build environment ********** -qt_env = env.Clone() -qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "DBus", "Xml"] - -qt_libs = [] -if arch == "Darwin": - qt_env['QTDIR'] = f"{brew_prefix}/opt/qt@5" - qt_dirs = [ - os.path.join(qt_env['QTDIR'], "include"), - ] - qt_dirs += [f"{qt_env['QTDIR']}/include/Qt{m}" for m in qt_modules] - qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")] - qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"] - qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin")) -else: - qt_install_prefix = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip() - qt_install_headers = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip() - - qt_env['QTDIR'] = qt_install_prefix - qt_dirs = [ - f"{qt_install_headers}", - ] - - qt_gui_path = os.path.join(qt_install_headers, "QtGui") - qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))] - qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else [] - qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules] - - qt_libs = [f"Qt5{m}" for m in qt_modules] - if arch == "larch64": - qt_libs += ["GLESv2", "wayland-client"] - qt_env.PrependENVPath('PATH', Dir("#third_party/qt5/larch64/bin/").abspath) - elif arch != "Darwin": - qt_libs += ["GL"] -qt_env['QT3DIR'] = qt_env['QTDIR'] -qt_env.Tool('qt3') - -qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"] -qt_flags = [ - "-D_REENTRANT", - "-DQT_NO_DEBUG", - "-DQT_WIDGETS_LIB", - "-DQT_GUI_LIB", - "-DQT_CORE_LIB", - "-DQT_MESSAGELOGCONTEXT", -] -qt_env['CXXFLAGS'] += qt_flags -qt_env['LIBPATH'] += ['#selfdrive/ui', ] -qt_env['LIBS'] = qt_libs - -Export('env', 'qt_env', 'arch') +Export('env', 'arch') # Setup cache dir cache_dir = '/data/scons_cache' if arch == "larch64" else '/tmp/scons_cache' diff --git a/pyproject.toml b/pyproject.toml index 6cc6298eb3..8cb877c351 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -177,7 +177,7 @@ quiet-level = 3 # if you've got a short variable name that's getting flagged, add it here ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite" builtin = "clear,rare,informal,code,names,en-GB_to_en-US" -skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, *.po, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*" +skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.po, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*" [tool.mypy] python_version = "3.11" diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index a7670b2482..a9b40f0d24 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,6 +1,9 @@ import os import json -Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') +Import('env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') + +raylib_env = env.Clone() + # compile gettext .po -> .mo translations with open(File("translations/languages.json").abspath) as f: @@ -11,101 +14,40 @@ po_sources = [src for src in po_sources if os.path.exists(File(src).abspath)] mo_targets = [src.replace(".po", ".mo") for src in po_sources] mo_build = [] for src, tgt in zip(po_sources, mo_targets): - mo_build.append(qt_env.Command(tgt, src, "msgfmt -o $TARGET $SOURCE")) -mo_alias = qt_env.Alias('mo', mo_build) -qt_env.AlwaysBuild(mo_alias) + mo_build.append(raylib_env.Command(tgt, src, "msgfmt -o $TARGET $SOURCE")) +mo_alias = raylib_env.Alias('mo', mo_build) +raylib_env.AlwaysBuild(mo_alias) if GetOption('extras'): - base_libs = [common, messaging, visionipc, transformations, - 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] - - if arch == 'larch64': - base_libs.append('EGL') - - if arch == "Darwin": - del base_libs[base_libs.index('OpenCL')] - qt_env['FRAMEWORKS'] += ['OpenCL'] - - # FIXME: remove this once we're on 5.15 (24.04) - qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] - - qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs) - widgets_src = ["qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/prime_state.cc", - "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", - "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", - "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", - "qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] - - widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs) - Export('widgets') - qt_libs = [widgets, qt_util] + base_libs - - qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc", - "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", - "qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc", - "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/offroad/firehose.cc", - "qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc", - "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"] - - # build translation files - translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.values()] - translation_targets = [src.replace(".ts", ".qm") for src in translation_sources] - lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease' - - lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES") - qt_env.NoClean(translation_sources) - qt_env.Precious(translation_sources) - - # create qrc file for compiled translations to include with assets - translations_assets_src = "#selfdrive/assets/translations_assets.qrc" - with open(File(translations_assets_src).abspath, 'w') as f: - f.write('\n\n') - f.write('\n'.join([f'../ui/translations/{l}.qm' for l in languages.values()])) - f.write('\n\n') - - # build assets - assets = "#selfdrive/assets/assets.cc" - assets_src = "#selfdrive/assets/assets.qrc" - qt_env.Command(assets, [assets_src, translations_assets_src], f"rcc $SOURCES -o $TARGET") - qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, translations_assets_src, "#selfdrive/assets/assets.o"]) + [lrelease]) - asset_obj = qt_env.Object("assets", assets) - - # build main UI - qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs) - if GetOption('extras'): - qt_src.remove("main.cc") # replaced by test_runner - qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs) - - # build installers - if arch != "Darwin": - raylib_env = env.Clone() - raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/'] - raylib_env['LINKFLAGS'].append('-Wl,-strip-debug') - - raylib_libs = common + ["raylib"] - if arch == "larch64": - raylib_libs += ["GLESv2", "EGL", "gbm", "drm"] - else: - raylib_libs += ["GL"] - - release = "release3" - installers = [ - ("openpilot", release), - ("openpilot_test", f"{release}-staging"), - ("openpilot_nightly", "nightly"), - ("openpilot_internal", "nightly-dev"), - ] - - cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh", - "ld -r -b binary -o $TARGET $SOURCE") - inter = raylib_env.Command("installer/inter_ttf.o", "installer/inter-ascii.ttf", - "ld -r -b binary -o $TARGET $SOURCE") - for name, branch in installers: - d = {'BRANCH': f"'\"{branch}\"'"} - if "internal" in name: - d['INTERNAL'] = "1" - - obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) - f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter], LIBS=raylib_libs) - # keep installers small - assert f[0].get_size() < 1900*1e3, f[0].get_size() + # build installers + if arch != "Darwin": + raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/'] + raylib_env['LINKFLAGS'].append('-Wl,-strip-debug') + + raylib_libs = common + ["raylib"] + if arch == "larch64": + raylib_libs += ["GLESv2", "EGL", "gbm", "drm"] + else: + raylib_libs += ["GL"] + + release = "release3" + installers = [ + ("openpilot", release), + ("openpilot_test", f"{release}-staging"), + ("openpilot_nightly", "nightly"), + ("openpilot_internal", "nightly-dev"), + ] + + cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh", + "ld -r -b binary -o $TARGET $SOURCE") + inter = raylib_env.Command("installer/inter_ttf.o", "installer/inter-ascii.ttf", + "ld -r -b binary -o $TARGET $SOURCE") + for name, branch in installers: + d = {'BRANCH': f"'\"{branch}\"'"} + if "internal" in name: + d['INTERNAL'] = "1" + + obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) + f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter], LIBS=raylib_libs) + # keep installers small + assert f[0].get_size() < 1900*1e3, f[0].get_size() diff --git a/selfdrive/ui/main.cc b/selfdrive/ui/main.cc deleted file mode 100644 index 4903a3db3d..0000000000 --- a/selfdrive/ui/main.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include - -#include -#include - -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/window.h" - -int main(int argc, char *argv[]) { - setpriority(PRIO_PROCESS, 0, -20); - - qInstallMessageHandler(swagLogMessageHandler); - initApp(argc, argv); - - QTranslator translator; - QString translation_file = QString::fromStdString(Params().get("LanguageSetting")); - if (!translator.load(QString(":/%1").arg(translation_file)) && translation_file.length()) { - qCritical() << "Failed to load translation file:" << translation_file; - } - - QApplication a(argc, argv); - a.installTranslator(&translator); - - MainWindow w; - setMainWindow(&w); - a.installEventFilter(&w); - return a.exec(); -} diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc deleted file mode 100644 index 6889b40e51..0000000000 --- a/selfdrive/ui/qt/api.cc +++ /dev/null @@ -1,142 +0,0 @@ -#include "selfdrive/ui/qt/api.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "common/util.h" -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/util.h" - -namespace CommaApi { - -RSA *get_rsa_private_key() { - static std::unique_ptr rsa_private(nullptr, RSA_free); - if (!rsa_private) { - FILE *fp = fopen(Path::rsa_file().c_str(), "rb"); - if (!fp) { - qDebug() << "No RSA private key found, please run manager.py or registration.py"; - return nullptr; - } - rsa_private.reset(PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)); - fclose(fp); - } - return rsa_private.get(); -} - -QByteArray rsa_sign(const QByteArray &data) { - RSA *rsa_private = get_rsa_private_key(); - if (!rsa_private) return {}; - - QByteArray sig(RSA_size(rsa_private), Qt::Uninitialized); - unsigned int sig_len; - int ret = RSA_sign(NID_sha256, (unsigned char*)data.data(), data.size(), (unsigned char*)sig.data(), &sig_len, rsa_private); - assert(ret == 1); - assert(sig.size() == sig_len); - return sig; -} - -QString create_jwt(const QJsonObject &payloads, int expiry) { - QJsonObject header = {{"alg", "RS256"}}; - - auto t = QDateTime::currentSecsSinceEpoch(); - QJsonObject payload = {{"identity", getDongleId().value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}}; - for (auto it = payloads.begin(); it != payloads.end(); ++it) { - payload.insert(it.key(), it.value()); - } - - auto b64_opts = QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals; - QString jwt = QJsonDocument(header).toJson(QJsonDocument::Compact).toBase64(b64_opts) + '.' + - QJsonDocument(payload).toJson(QJsonDocument::Compact).toBase64(b64_opts); - - auto hash = QCryptographicHash::hash(jwt.toUtf8(), QCryptographicHash::Sha256); - return jwt + "." + rsa_sign(hash).toBase64(b64_opts); -} - -} // namespace CommaApi - -HttpRequest::HttpRequest(QObject *parent, bool create_jwt, int timeout) : create_jwt(create_jwt), QObject(parent) { - networkTimer = new QTimer(this); - networkTimer->setSingleShot(true); - networkTimer->setInterval(timeout); - connect(networkTimer, &QTimer::timeout, this, &HttpRequest::requestTimeout); -} - -bool HttpRequest::active() const { - return reply != nullptr; -} - -bool HttpRequest::timeout() const { - return reply && reply->error() == QNetworkReply::OperationCanceledError; -} - -void HttpRequest::sendRequest(const QString &requestURL, const HttpRequest::Method method) { - if (active()) { - qDebug() << "HttpRequest is active"; - return; - } - QString token; - if (create_jwt) { - token = CommaApi::create_jwt(); - } else { - QString token_json = QString::fromStdString(util::read_file(util::getenv("HOME") + "/.comma/auth.json")); - QJsonDocument json_d = QJsonDocument::fromJson(token_json.toUtf8()); - token = json_d["access_token"].toString(); - } - - QNetworkRequest request; - request.setUrl(QUrl(requestURL)); - request.setRawHeader("User-Agent", getUserAgent().toUtf8()); - - if (!token.isEmpty()) { - request.setRawHeader(QByteArray("Authorization"), ("JWT " + token).toUtf8()); - } - - if (method == HttpRequest::Method::GET) { - reply = nam()->get(request); - } else if (method == HttpRequest::Method::DELETE) { - reply = nam()->deleteResource(request); - } - - networkTimer->start(); - connect(reply, &QNetworkReply::finished, this, &HttpRequest::requestFinished); -} - -void HttpRequest::requestTimeout() { - reply->abort(); -} - -void HttpRequest::requestFinished() { - networkTimer->stop(); - - if (reply->error() == QNetworkReply::NoError) { - emit requestDone(reply->readAll(), true, reply->error()); - } else { - QString error; - if (reply->error() == QNetworkReply::OperationCanceledError) { - nam()->clearAccessCache(); - nam()->clearConnectionCache(); - error = "Request timed out"; - } else { - error = reply->errorString(); - } - emit requestDone(error, false, reply->error()); - } - - reply->deleteLater(); - reply = nullptr; -} - -QNetworkAccessManager *HttpRequest::nam() { - static QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager(qApp); - return networkAccessManager; -} diff --git a/selfdrive/ui/qt/api.h b/selfdrive/ui/qt/api.h deleted file mode 100644 index ad64d7e722..0000000000 --- a/selfdrive/ui/qt/api.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "common/util.h" - -namespace CommaApi { - -const QString BASE_URL = util::getenv("API_HOST", "https://api.commadotai.com").c_str(); -QByteArray rsa_sign(const QByteArray &data); -QString create_jwt(const QJsonObject &payloads = {}, int expiry = 3600); - -} // namespace CommaApi - -/** - * Makes a request to the request endpoint. - */ - -class HttpRequest : public QObject { - Q_OBJECT - -public: - enum class Method {GET, DELETE}; - - explicit HttpRequest(QObject* parent, bool create_jwt = true, int timeout = 20000); - void sendRequest(const QString &requestURL, const Method method = Method::GET); - bool active() const; - bool timeout() const; - -signals: - void requestDone(const QString &response, bool success, QNetworkReply::NetworkError error); - -protected: - QNetworkReply *reply = nullptr; - -private: - static QNetworkAccessManager *nam(); - QTimer *networkTimer = nullptr; - bool create_jwt; - -private slots: - void requestTimeout(); - void requestFinished(); -}; diff --git a/selfdrive/ui/qt/body.cc b/selfdrive/ui/qt/body.cc deleted file mode 100644 index e01adbe063..0000000000 --- a/selfdrive/ui/qt/body.cc +++ /dev/null @@ -1,161 +0,0 @@ -#include "selfdrive/ui/qt/body.h" - -#include -#include - -#include -#include - -#include "common/params.h" -#include "common/timing.h" - -RecordButton::RecordButton(QWidget *parent) : QPushButton(parent) { - setCheckable(true); - setChecked(false); - setFixedSize(148, 148); - - QObject::connect(this, &QPushButton::toggled, [=]() { - setEnabled(false); - }); -} - -void RecordButton::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - QPoint center(width() / 2, height() / 2); - - QColor bg(isChecked() ? "#FFFFFF" : "#737373"); - QColor accent(isChecked() ? "#FF0000" : "#FFFFFF"); - if (!isEnabled()) { - bg = QColor("#404040"); - accent = QColor("#FFFFFF"); - } - - if (isDown()) { - accent.setAlphaF(0.7); - } - - p.setPen(Qt::NoPen); - p.setBrush(bg); - p.drawEllipse(center, 74, 74); - - p.setPen(QPen(accent, 6)); - p.setBrush(Qt::NoBrush); - p.drawEllipse(center, 42, 42); - - p.setPen(Qt::NoPen); - p.setBrush(accent); - p.drawEllipse(center, 22, 22); -} - - -BodyWindow::BodyWindow(QWidget *parent) : fuel_filter(1.0, 5., 1. / UI_FREQ), QWidget(parent) { - QStackedLayout *layout = new QStackedLayout(this); - layout->setStackingMode(QStackedLayout::StackAll); - - QWidget *w = new QWidget; - QVBoxLayout *vlayout = new QVBoxLayout(w); - vlayout->setMargin(45); - layout->addWidget(w); - - // face - face = new QLabel(); - face->setAlignment(Qt::AlignCenter); - layout->addWidget(face); - awake = new QMovie("../assets/body/awake.gif", {}, this); - awake->setCacheMode(QMovie::CacheAll); - sleep = new QMovie("../assets/body/sleep.gif", {}, this); - sleep->setCacheMode(QMovie::CacheAll); - - // record button - btn = new RecordButton(this); - vlayout->addWidget(btn, 0, Qt::AlignBottom | Qt::AlignRight); - QObject::connect(btn, &QPushButton::clicked, [=](bool checked) { - btn->setEnabled(false); - Params().putBool("DisableLogging", !checked); - last_button = nanos_since_boot(); - }); - w->raise(); - - QObject::connect(uiState(), &UIState::uiUpdate, this, &BodyWindow::updateState); -} - -void BodyWindow::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - p.fillRect(rect(), QColor(0, 0, 0)); - - // battery outline + detail - p.translate(width() - 136, 16); - const QColor gray = QColor("#737373"); - p.setBrush(Qt::NoBrush); - p.setPen(QPen(gray, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - p.drawRoundedRect(2, 2, 78, 36, 8, 8); - - p.setPen(Qt::NoPen); - p.setBrush(gray); - p.drawRoundedRect(84, 12, 6, 16, 4, 4); - p.drawRect(84, 12, 3, 16); - - // battery level - double fuel = std::clamp(fuel_filter.x(), 0.2f, 1.0f); - const int m = 5; // manual margin since we can't do an inner border - p.setPen(Qt::NoPen); - p.setBrush(fuel > 0.25 ? QColor("#32D74B") : QColor("#FF453A")); - p.drawRoundedRect(2 + m, 2 + m, (78 - 2*m)*fuel, 36 - 2*m, 4, 4); - - // charging status - if (charging) { - p.setPen(Qt::NoPen); - p.setBrush(Qt::white); - const QPolygonF charger({ - QPointF(12.31, 0), - QPointF(12.31, 16.92), - QPointF(18.46, 16.92), - QPointF(6.15, 40), - QPointF(6.15, 23.08), - QPointF(0, 23.08), - }); - p.drawPolygon(charger.translated(98, 0)); - } -} - -void BodyWindow::offroadTransition(bool offroad) { - btn->setChecked(true); - btn->setEnabled(true); - fuel_filter.reset(1.0); -} - -void BodyWindow::updateState(const UIState &s) { - if (!isVisible()) { - return; - } - - const SubMaster &sm = *(s.sm); - auto cs = sm["carState"].getCarState(); - - charging = cs.getCharging(); - fuel_filter.update(cs.getFuelGauge()); - - // TODO: use carState.standstill when that's fixed - const bool standstill = std::abs(cs.getVEgo()) < 0.01; - QMovie *m = standstill ? sleep : awake; - if (m != face->movie()) { - face->setMovie(m); - face->movie()->start(); - } - - // update record button state - if (sm.updated("managerState") && (sm.rcv_time("managerState") - last_button)*1e-9 > 0.5) { - for (auto proc : sm["managerState"].getManagerState().getProcesses()) { - if (proc.getName() == "loggerd") { - btn->setEnabled(true); - btn->setChecked(proc.getRunning()); - } - } - } - - update(); -} diff --git a/selfdrive/ui/qt/body.h b/selfdrive/ui/qt/body.h deleted file mode 100644 index 567a54d49b..0000000000 --- a/selfdrive/ui/qt/body.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "common/util.h" -#include "selfdrive/ui/ui.h" - -class RecordButton : public QPushButton { - Q_OBJECT - -public: - RecordButton(QWidget* parent = 0); - -private: - void paintEvent(QPaintEvent*) override; -}; - -class BodyWindow : public QWidget { - Q_OBJECT - -public: - BodyWindow(QWidget* parent = 0); - -private: - bool charging = false; - uint64_t last_button = 0; - FirstOrderFilter fuel_filter; - QLabel *face; - QMovie *awake, *sleep; - RecordButton *btn; - void paintEvent(QPaintEvent*) override; - -private slots: - void updateState(const UIState &s); - void offroadTransition(bool onroad); -}; diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc deleted file mode 100644 index 8b1fdf474c..0000000000 --- a/selfdrive/ui/qt/home.cc +++ /dev/null @@ -1,243 +0,0 @@ -#include "selfdrive/ui/qt/home.h" - -#include -#include -#include -#include - -#include "selfdrive/ui/qt/offroad/experimental_mode.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/prime.h" - -// HomeWindow: the container for the offroad and onroad UIs - -HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { - QHBoxLayout *main_layout = new QHBoxLayout(this); - main_layout->setMargin(0); - main_layout->setSpacing(0); - - sidebar = new Sidebar(this); - main_layout->addWidget(sidebar); - QObject::connect(sidebar, &Sidebar::openSettings, this, &HomeWindow::openSettings); - - slayout = new QStackedLayout(); - main_layout->addLayout(slayout); - - home = new OffroadHome(this); - QObject::connect(home, &OffroadHome::openSettings, this, &HomeWindow::openSettings); - slayout->addWidget(home); - - onroad = new OnroadWindow(this); - slayout->addWidget(onroad); - - body = new BodyWindow(this); - slayout->addWidget(body); - - driver_view = new DriverViewWindow(this); - connect(driver_view, &DriverViewWindow::done, [=] { - showDriverView(false); - }); - slayout->addWidget(driver_view); - setAttribute(Qt::WA_NoSystemBackground); - QObject::connect(uiState(), &UIState::uiUpdate, this, &HomeWindow::updateState); - QObject::connect(uiState(), &UIState::offroadTransition, this, &HomeWindow::offroadTransition); - QObject::connect(uiState(), &UIState::offroadTransition, sidebar, &Sidebar::offroadTransition); -} - -void HomeWindow::showSidebar(bool show) { - sidebar->setVisible(show); -} - -void HomeWindow::updateState(const UIState &s) { - const SubMaster &sm = *(s.sm); - - // switch to the generic robot UI - if (onroad->isVisible() && !body->isEnabled() && sm["carParams"].getCarParams().getNotCar()) { - body->setEnabled(true); - slayout->setCurrentWidget(body); - } -} - -void HomeWindow::offroadTransition(bool offroad) { - body->setEnabled(false); - sidebar->setVisible(offroad); - if (offroad) { - slayout->setCurrentWidget(home); - } else { - slayout->setCurrentWidget(onroad); - } -} - -void HomeWindow::showDriverView(bool show) { - if (show) { - emit closeSettings(); - slayout->setCurrentWidget(driver_view); - } else { - slayout->setCurrentWidget(home); - } - sidebar->setVisible(show == false); -} - -void HomeWindow::mousePressEvent(QMouseEvent* e) { - // Handle sidebar collapsing - if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) { - sidebar->setVisible(!sidebar->isVisible()); - } -} - -void HomeWindow::mouseDoubleClickEvent(QMouseEvent* e) { - HomeWindow::mousePressEvent(e); - const SubMaster &sm = *(uiState()->sm); - if (sm["carParams"].getCarParams().getNotCar()) { - if (onroad->isVisible()) { - slayout->setCurrentWidget(body); - } else if (body->isVisible()) { - slayout->setCurrentWidget(onroad); - } - showSidebar(false); - } -} - -// OffroadHome: the offroad home page - -OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(40, 40, 40, 40); - - // top header - QHBoxLayout* header_layout = new QHBoxLayout(); - header_layout->setContentsMargins(0, 0, 0, 0); - header_layout->setSpacing(16); - - update_notif = new QPushButton(tr("UPDATE")); - update_notif->setVisible(false); - update_notif->setStyleSheet("background-color: #364DEF;"); - QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); }); - header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); - - alert_notif = new QPushButton(); - alert_notif->setVisible(false); - alert_notif->setStyleSheet("background-color: #E22C2C;"); - QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); }); - header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); - - version = new ElidedLabel(); - header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight); - - main_layout->addLayout(header_layout); - - // main content - main_layout->addSpacing(25); - center_layout = new QStackedLayout(); - - QWidget *home_widget = new QWidget(this); - { - QHBoxLayout *home_layout = new QHBoxLayout(home_widget); - home_layout->setContentsMargins(0, 0, 0, 0); - home_layout->setSpacing(30); - - // left: PrimeAdWidget - QStackedWidget *left_widget = new QStackedWidget(this); - QVBoxLayout *left_prime_layout = new QVBoxLayout(); - left_prime_layout->setContentsMargins(0, 0, 0, 0); - QWidget *prime_user = new PrimeUserWidget(); - prime_user->setStyleSheet(R"( - border-radius: 10px; - background-color: #333333; - )"); - left_prime_layout->addWidget(prime_user); - left_prime_layout->addStretch(); - left_widget->addWidget(new LayoutWidget(left_prime_layout)); - left_widget->addWidget(new PrimeAdWidget); - left_widget->setStyleSheet("border-radius: 10px;"); - - connect(uiState()->prime_state, &PrimeState::changed, [left_widget]() { - left_widget->setCurrentIndex(uiState()->prime_state->isSubscribed() ? 0 : 1); - }); - - home_layout->addWidget(left_widget, 1); - - // right: ExperimentalModeButton, SetupWidget - QWidget* right_widget = new QWidget(this); - QVBoxLayout* right_column = new QVBoxLayout(right_widget); - right_column->setContentsMargins(0, 0, 0, 0); - right_widget->setFixedWidth(750); - right_column->setSpacing(30); - - ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); - QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); - right_column->addWidget(experimental_mode, 1); - - SetupWidget *setup_widget = new SetupWidget; - QObject::connect(setup_widget, &SetupWidget::openSettings, this, &OffroadHome::openSettings); - right_column->addWidget(setup_widget, 1); - - home_layout->addWidget(right_widget, 1); - } - center_layout->addWidget(home_widget); - - // add update & alerts widgets - update_widget = new UpdateAlert(); - QObject::connect(update_widget, &UpdateAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); }); - center_layout->addWidget(update_widget); - alerts_widget = new OffroadAlert(); - QObject::connect(alerts_widget, &OffroadAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); }); - center_layout->addWidget(alerts_widget); - - main_layout->addLayout(center_layout, 1); - - // set up refresh timer - timer = new QTimer(this); - timer->callOnTimeout(this, &OffroadHome::refresh); - - setStyleSheet(R"( - * { - color: white; - } - OffroadHome { - background-color: black; - } - OffroadHome > QPushButton { - padding: 15px 30px; - border-radius: 5px; - font-size: 40px; - font-weight: 500; - } - OffroadHome > QLabel { - font-size: 55px; - } - )"); -} - -void OffroadHome::showEvent(QShowEvent *event) { - refresh(); - timer->start(10 * 1000); -} - -void OffroadHome::hideEvent(QHideEvent *event) { - timer->stop(); -} - -void OffroadHome::refresh() { - version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription"))); - - bool updateAvailable = update_widget->refresh(); - int alerts = alerts_widget->refresh(); - - // pop-up new notification - int idx = center_layout->currentIndex(); - if (!updateAvailable && !alerts) { - idx = 0; - } else if (updateAvailable && (!update_notif->isVisible() || (!alerts && idx == 2))) { - idx = 1; - } else if (alerts && (!alert_notif->isVisible() || (!updateAvailable && idx == 1))) { - idx = 2; - } - center_layout->setCurrentIndex(idx); - - update_notif->setVisible(updateAvailable); - alert_notif->setVisible(alerts); - if (alerts) { - alert_notif->setText(QString::number(alerts) + (alerts > 1 ? tr(" ALERTS") : tr(" ALERT"))); - } -} diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h deleted file mode 100644 index a19b70ac3f..0000000000 --- a/selfdrive/ui/qt/home.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/offroad/driverview.h" -#include "selfdrive/ui/qt/body.h" -#include "selfdrive/ui/qt/onroad/onroad_home.h" -#include "selfdrive/ui/qt/sidebar.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/offroad_alerts.h" -#include "selfdrive/ui/ui.h" - -class OffroadHome : public QFrame { - Q_OBJECT - -public: - explicit OffroadHome(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString ¶m = ""); - -private: - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - void refresh(); - - Params params; - - QTimer* timer; - ElidedLabel* version; - QStackedLayout* center_layout; - UpdateAlert *update_widget; - OffroadAlert* alerts_widget; - QPushButton* alert_notif; - QPushButton* update_notif; -}; - -class HomeWindow : public QWidget { - Q_OBJECT - -public: - explicit HomeWindow(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString ¶m = ""); - void closeSettings(); - -public slots: - void offroadTransition(bool offroad); - void showDriverView(bool show); - void showSidebar(bool show); - -protected: - void mousePressEvent(QMouseEvent* e) override; - void mouseDoubleClickEvent(QMouseEvent* e) override; - -private: - Sidebar *sidebar; - OffroadHome *home; - OnroadWindow *onroad; - BodyWindow *body; - DriverViewWindow *driver_view; - QStackedLayout *slayout; - -private slots: - void updateState(const UIState &s); -}; diff --git a/selfdrive/ui/qt/network/networking.cc b/selfdrive/ui/qt/network/networking.cc deleted file mode 100644 index f19786a46f..0000000000 --- a/selfdrive/ui/qt/network/networking.cc +++ /dev/null @@ -1,413 +0,0 @@ -#include "selfdrive/ui/qt/network/networking.h" - -#include - -#include -#include -#include - -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -static const int ICON_WIDTH = 49; - -// Networking functions - -Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) { - main_layout = new QStackedLayout(this); - - wifi = new WifiManager(this); - connect(wifi, &WifiManager::refreshSignal, this, &Networking::refresh); - connect(wifi, &WifiManager::wrongPassword, this, &Networking::wrongPassword); - - wifiScreen = new QWidget(this); - QVBoxLayout* vlayout = new QVBoxLayout(wifiScreen); - vlayout->setContentsMargins(20, 20, 20, 20); - if (show_advanced) { - QPushButton* advancedSettings = new QPushButton(tr("Advanced")); - advancedSettings->setObjectName("advanced_btn"); - advancedSettings->setStyleSheet("margin-right: 30px;"); - advancedSettings->setFixedSize(400, 100); - connect(advancedSettings, &QPushButton::clicked, [=]() { main_layout->setCurrentWidget(an); }); - vlayout->addSpacing(10); - vlayout->addWidget(advancedSettings, 0, Qt::AlignRight); - vlayout->addSpacing(10); - } - - wifiWidget = new WifiUI(this, wifi); - wifiWidget->setObjectName("wifiWidget"); - connect(wifiWidget, &WifiUI::connectToNetwork, this, &Networking::connectToNetwork); - - ScrollView *wifiScroller = new ScrollView(wifiWidget, this); - wifiScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - vlayout->addWidget(wifiScroller, 1); - main_layout->addWidget(wifiScreen); - - an = new AdvancedNetworking(this, wifi); - connect(an, &AdvancedNetworking::backPress, [=]() { main_layout->setCurrentWidget(wifiScreen); }); - connect(an, &AdvancedNetworking::requestWifiScreen, [=]() { main_layout->setCurrentWidget(wifiScreen); }); - main_layout->addWidget(an); - - QPalette pal = palette(); - pal.setColor(QPalette::Window, QColor(0x29, 0x29, 0x29)); - setAutoFillBackground(true); - setPalette(pal); - - setStyleSheet(R"( - #wifiWidget > QPushButton, #back_btn, #advanced_btn { - font-size: 50px; - margin: 0px; - padding: 15px; - border-width: 0; - border-radius: 30px; - color: #dddddd; - background-color: #393939; - } - #back_btn:pressed, #advanced_btn:pressed { - background-color: #4a4a4a; - } - )"); - main_layout->setCurrentWidget(wifiScreen); -} - -void Networking::setPrimeType(PrimeState::Type type) { - an->setGsmVisible(type == PrimeState::PRIME_TYPE_NONE || type == PrimeState::PRIME_TYPE_LITE); - wifi->ipv4_forward = (type == PrimeState::PRIME_TYPE_NONE || type == PrimeState::PRIME_TYPE_LITE); -} - -void Networking::refresh() { - wifiWidget->refresh(); - an->refresh(); -} - -void Networking::connectToNetwork(const Network n) { - if (wifi->isKnownConnection(n.ssid)) { - wifi->activateWifiConnection(n.ssid); - } else if (n.security_type == SecurityType::OPEN) { - wifi->connect(n, false); - } else if (n.security_type == SecurityType::WPA) { - QString pass = InputDialog::getText(tr("Enter password"), this, tr("for \"%1\"").arg(QString::fromUtf8(n.ssid)), true, 8); - if (!pass.isEmpty()) { - wifi->connect(n, false, pass); - } - } -} - -void Networking::wrongPassword(const QString &ssid) { - if (wifi->seenNetworks.contains(ssid)) { - const Network &n = wifi->seenNetworks.value(ssid); - QString pass = InputDialog::getText(tr("Wrong password"), this, tr("for \"%1\"").arg(QString::fromUtf8(n.ssid)), true, 8); - if (!pass.isEmpty()) { - wifi->connect(n, false, pass); - } - } -} - -void Networking::showEvent(QShowEvent *event) { - wifi->start(); -} - -void Networking::hideEvent(QHideEvent *event) { - main_layout->setCurrentWidget(wifiScreen); - wifi->stop(); -} - -// AdvancedNetworking functions - -AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi) { - - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setMargin(40); - main_layout->setSpacing(20); - - // Back button - QPushButton* back = new QPushButton(tr("Back")); - back->setObjectName("back_btn"); - back->setFixedSize(400, 100); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - main_layout->addWidget(back, 0, Qt::AlignLeft); - - ListWidget *list = new ListWidget(this); - // Enable tethering layout - tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled()); - list->addItem(tetheringToggle); - QObject::connect(tetheringToggle, &ToggleControl::toggleFlipped, this, &AdvancedNetworking::toggleTethering); - - // Change tethering password - ButtonControl *editPasswordButton = new ButtonControl(tr("Tethering Password"), tr("EDIT")); - connect(editPasswordButton, &ButtonControl::clicked, [=]() { - QString pass = InputDialog::getText(tr("Enter new tethering password"), this, "", true, 8, wifi->getTetheringPassword()); - if (!pass.isEmpty()) { - wifi->changeTetheringPassword(pass); - } - }); - list->addItem(editPasswordButton); - - // IP address - ipLabel = new LabelControl(tr("IP Address"), wifi->ipv4_address); - list->addItem(ipLabel); - - // Roaming toggle - const bool roamingEnabled = params.getBool("GsmRoaming"); - roamingToggle = new ToggleControl(tr("Enable Roaming"), "", "", roamingEnabled); - QObject::connect(roamingToggle, &ToggleControl::toggleFlipped, [=](bool state) { - params.putBool("GsmRoaming", state); - wifi->updateGsmSettings(state, QString::fromStdString(params.get("GsmApn")), params.getBool("GsmMetered")); - }); - list->addItem(roamingToggle); - - // APN settings - editApnButton = new ButtonControl(tr("APN Setting"), tr("EDIT")); - connect(editApnButton, &ButtonControl::clicked, [=]() { - const QString cur_apn = QString::fromStdString(params.get("GsmApn")); - QString apn = InputDialog::getText(tr("Enter APN"), this, tr("leave blank for automatic configuration"), false, -1, cur_apn).trimmed(); - - if (apn.isEmpty()) { - params.remove("GsmApn"); - } else { - params.put("GsmApn", apn.toStdString()); - } - wifi->updateGsmSettings(params.getBool("GsmRoaming"), apn, params.getBool("GsmMetered")); - }); - list->addItem(editApnButton); - - // Cellular metered toggle (prime lite or none) - const bool metered = params.getBool("GsmMetered"); - cellularMeteredToggle = new ToggleControl(tr("Cellular Metered"), tr("Prevent large data uploads when on a metered cellular connection"), "", metered); - QObject::connect(cellularMeteredToggle, &SshToggle::toggleFlipped, [=](bool state) { - params.putBool("GsmMetered", state); - wifi->updateGsmSettings(params.getBool("GsmRoaming"), QString::fromStdString(params.get("GsmApn")), state); - }); - list->addItem(cellularMeteredToggle); - - // Wi-Fi metered toggle - std::vector metered_button_texts{tr("default"), tr("metered"), tr("unmetered")}; - wifiMeteredToggle = new MultiButtonControl(tr("Wi-Fi Network Metered"), tr("Prevent large data uploads when on a metered Wi-Fi connection"), "", metered_button_texts); - QObject::connect(wifiMeteredToggle, &MultiButtonControl::buttonClicked, [=](int id) { - wifiMeteredToggle->setEnabled(false); - MeteredType metered = MeteredType::UNKNOWN; - if (id == NM_METERED_YES) { - metered = MeteredType::YES; - } else if (id == NM_METERED_NO) { - metered = MeteredType::NO; - } - auto pending_call = wifi->setCurrentNetworkMetered(metered); - if (pending_call) { - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(*pending_call); - QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [=]() { - refresh(); - watcher->deleteLater(); - }); - } - }); - list->addItem(wifiMeteredToggle); - - // Hidden Network - hiddenNetworkButton = new ButtonControl(tr("Hidden Network"), tr("CONNECT")); - connect(hiddenNetworkButton, &ButtonControl::clicked, [=]() { - QString ssid = InputDialog::getText(tr("Enter SSID"), this, "", false, 1); - if (!ssid.isEmpty()) { - QString pass = InputDialog::getText(tr("Enter password"), this, tr("for \"%1\"").arg(ssid), true, -1); - Network hidden_network; - hidden_network.ssid = ssid.toUtf8(); - if (!pass.isEmpty()) { - hidden_network.security_type = SecurityType::WPA; - wifi->connect(hidden_network, true, pass); - } else { - wifi->connect(hidden_network, true); - } - emit requestWifiScreen(); - } - }); - list->addItem(hiddenNetworkButton); - - // Set initial config - wifi->updateGsmSettings(roamingEnabled, QString::fromStdString(params.get("GsmApn")), metered); - - main_layout->addWidget(new ScrollView(list, this)); - main_layout->addStretch(1); -} - -void AdvancedNetworking::setGsmVisible(bool visible) { - roamingToggle->setVisible(visible); - editApnButton->setVisible(visible); - cellularMeteredToggle->setVisible(visible); -} - -void AdvancedNetworking::refresh() { - ipLabel->setText(wifi->ipv4_address); - tetheringToggle->setEnabled(true); - - if (wifi->isTetheringEnabled() || wifi->ipv4_address == "") { - wifiMeteredToggle->setEnabled(false); - wifiMeteredToggle->setCheckedButton(0); - } else if (wifi->ipv4_address != "") { - MeteredType metered = wifi->currentNetworkMetered(); - wifiMeteredToggle->setEnabled(true); - wifiMeteredToggle->setCheckedButton(static_cast(metered)); - } - - update(); -} - -void AdvancedNetworking::toggleTethering(bool enabled) { - wifi->setTetheringEnabled(enabled); - tetheringToggle->setEnabled(false); - if (enabled) { - wifiMeteredToggle->setEnabled(false); - wifiMeteredToggle->setCheckedButton(0); - } -} - -// WifiUI functions - -WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - main_layout->setSpacing(0); - - // load imgs - for (const auto &s : {"low", "medium", "high", "full"}) { - QPixmap pix(ASSET_PATH + "/icons/wifi_strength_" + s + ".svg"); - strengths.push_back(pix.scaledToHeight(68, Qt::SmoothTransformation)); - } - lock = QPixmap(ASSET_PATH + "icons/lock_closed.svg").scaledToWidth(ICON_WIDTH, Qt::SmoothTransformation); - checkmark = QPixmap(ASSET_PATH + "icons/checkmark.svg").scaledToWidth(ICON_WIDTH, Qt::SmoothTransformation); - circled_slash = QPixmap(ASSET_PATH + "icons/circled_slash.svg").scaledToWidth(ICON_WIDTH, Qt::SmoothTransformation); - - scanningLabel = new QLabel(tr("Scanning for networks...")); - scanningLabel->setStyleSheet("font-size: 65px;"); - main_layout->addWidget(scanningLabel, 0, Qt::AlignCenter); - - wifi_list_widget = new ListWidget(this); - wifi_list_widget->setVisible(false); - main_layout->addWidget(wifi_list_widget); - - setStyleSheet(R"( - QScrollBar::handle:vertical { - min-height: 0px; - border-radius: 4px; - background-color: #8A8A8A; - } - #forgetBtn { - font-size: 32px; - font-weight: 600; - color: #292929; - background-color: #BDBDBD; - border-width: 1px solid #828282; - border-radius: 5px; - padding: 40px; - padding-bottom: 16px; - padding-top: 16px; - } - #forgetBtn:pressed { - background-color: #828282; - } - #connecting { - font-size: 32px; - font-weight: 600; - color: white; - border-radius: 0; - padding: 27px; - padding-left: 43px; - padding-right: 43px; - background-color: black; - } - #ssidLabel { - text-align: left; - border: none; - padding-top: 50px; - padding-bottom: 50px; - } - #ssidLabel:disabled { - color: #696969; - } - )"); -} - -void WifiUI::refresh() { - bool is_empty = wifi->seenNetworks.isEmpty(); - scanningLabel->setVisible(is_empty); - wifi_list_widget->setVisible(!is_empty); - if (is_empty) return; - - setUpdatesEnabled(false); - - const bool is_tethering_enabled = wifi->isTetheringEnabled(); - QList sortedNetworks = wifi->seenNetworks.values(); - std::sort(sortedNetworks.begin(), sortedNetworks.end(), compare_by_strength); - - int n = 0; - for (Network &network : sortedNetworks) { - QPixmap status_icon; - if (network.connected == ConnectedType::CONNECTED) { - status_icon = checkmark; - } else if (network.security_type == SecurityType::UNSUPPORTED) { - status_icon = circled_slash; - } else if (network.security_type == SecurityType::WPA) { - status_icon = lock; - } - bool show_forget_btn = wifi->isKnownConnection(network.ssid) && !is_tethering_enabled; - QPixmap strength = strengths[strengthLevel(network.strength)]; - - auto item = getItem(n++); - item->setItem(network, status_icon, show_forget_btn, strength); - item->setVisible(true); - } - for (; n < wifi_items.size(); ++n) wifi_items[n]->setVisible(false); - - setUpdatesEnabled(true); -} - -WifiItem *WifiUI::getItem(int n) { - auto item = n < wifi_items.size() ? wifi_items[n] : wifi_items.emplace_back(new WifiItem(tr("CONNECTING..."), tr("FORGET"))); - if (!item->parentWidget()) { - QObject::connect(item, &WifiItem::connectToNetwork, this, &WifiUI::connectToNetwork); - QObject::connect(item, &WifiItem::forgotNetwork, [this](const Network n) { - if (ConfirmationDialog::confirm(tr("Forget Wi-Fi Network \"%1\"?").arg(QString::fromUtf8(n.ssid)), tr("Forget"), this)) - wifi->forgetConnection(n.ssid); - }); - wifi_list_widget->addItem(item); - } - return item; -} - -// WifiItem - -WifiItem::WifiItem(const QString &connecting_text, const QString &forget_text, QWidget *parent) : QWidget(parent) { - QHBoxLayout *hlayout = new QHBoxLayout(this); - hlayout->setContentsMargins(44, 0, 73, 0); - hlayout->setSpacing(50); - - hlayout->addWidget(ssidLabel = new ElidedLabel()); - ssidLabel->setObjectName("ssidLabel"); - ssidLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - hlayout->addWidget(connecting = new QPushButton(connecting_text), 0, Qt::AlignRight); - connecting->setObjectName("connecting"); - hlayout->addWidget(forgetBtn = new QPushButton(forget_text), 0, Qt::AlignRight); - forgetBtn->setObjectName("forgetBtn"); - hlayout->addWidget(iconLabel = new QLabel(), 0, Qt::AlignRight); - hlayout->addWidget(strengthLabel = new QLabel(), 0, Qt::AlignRight); - - iconLabel->setFixedWidth(ICON_WIDTH); - QObject::connect(forgetBtn, &QPushButton::clicked, [this]() { emit forgotNetwork(network); }); - QObject::connect(ssidLabel, &ElidedLabel::clicked, [this]() { - if (network.connected == ConnectedType::DISCONNECTED) emit connectToNetwork(network); - }); -} - -void WifiItem::setItem(const Network &n, const QPixmap &status_icon, bool show_forget_btn, const QPixmap &strength_icon) { - network = n; - - ssidLabel->setText(n.ssid); - ssidLabel->setEnabled(n.security_type != SecurityType::UNSUPPORTED); - ssidLabel->setFont(InterFont(55, network.connected == ConnectedType::DISCONNECTED ? QFont::Normal : QFont::Bold)); - - connecting->setVisible(n.connected == ConnectedType::CONNECTING); - forgetBtn->setVisible(show_forget_btn); - - iconLabel->setPixmap(status_icon); - strengthLabel->setPixmap(strength_icon); -} diff --git a/selfdrive/ui/qt/network/networking.h b/selfdrive/ui/qt/network/networking.h deleted file mode 100644 index 0bdf64e459..0000000000 --- a/selfdrive/ui/qt/network/networking.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/ui/qt/network/wifi_manager.h" -#include "selfdrive/ui/qt/prime_state.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/qt/widgets/ssh_keys.h" -#include "selfdrive/ui/qt/widgets/toggle.h" - -class WifiItem : public QWidget { - Q_OBJECT -public: - explicit WifiItem(const QString &connecting_text, const QString &forget_text, QWidget* parent = nullptr); - void setItem(const Network& n, const QPixmap &icon, bool show_forget_btn, const QPixmap &strength); - -signals: - // Cannot pass Network by reference. it may change after the signal is sent. - void connectToNetwork(const Network n); - void forgotNetwork(const Network n); - -protected: - ElidedLabel* ssidLabel; - QPushButton* connecting; - QPushButton* forgetBtn; - QLabel* iconLabel; - QLabel* strengthLabel; - Network network; -}; - -class WifiUI : public QWidget { - Q_OBJECT - -public: - explicit WifiUI(QWidget *parent = 0, WifiManager* wifi = 0); - -private: - WifiItem *getItem(int n); - - WifiManager *wifi = nullptr; - QLabel *scanningLabel = nullptr; - QPixmap lock; - QPixmap checkmark; - QPixmap circled_slash; - QVector strengths; - ListWidget *wifi_list_widget = nullptr; - std::vector wifi_items; - -signals: - void connectToNetwork(const Network n); - -public slots: - void refresh(); -}; - -class AdvancedNetworking : public QWidget { - Q_OBJECT -public: - explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0); - void setGsmVisible(bool visible); - -private: - LabelControl* ipLabel; - ToggleControl* tetheringToggle; - ToggleControl* roamingToggle; - ButtonControl* editApnButton; - ButtonControl* hiddenNetworkButton; - ToggleControl* cellularMeteredToggle; - MultiButtonControl* wifiMeteredToggle; - WifiManager* wifi = nullptr; - Params params; - -signals: - void backPress(); - void requestWifiScreen(); - -public slots: - void toggleTethering(bool enabled); - void refresh(); -}; - -class Networking : public QFrame { - Q_OBJECT - -public: - explicit Networking(QWidget* parent = 0, bool show_advanced = true); - void setPrimeType(PrimeState::Type type); - WifiManager* wifi = nullptr; - -private: - QStackedLayout* main_layout = nullptr; - QWidget* wifiScreen = nullptr; - AdvancedNetworking* an = nullptr; - WifiUI* wifiWidget; - - void showEvent(QShowEvent* event) override; - void hideEvent(QHideEvent* event) override; - -public slots: - void refresh(); - -private slots: - void connectToNetwork(const Network n); - void wrongPassword(const QString &ssid); -}; diff --git a/selfdrive/ui/qt/network/networkmanager.h b/selfdrive/ui/qt/network/networkmanager.h deleted file mode 100644 index 8bdeaf3bbd..0000000000 --- a/selfdrive/ui/qt/network/networkmanager.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -/** - * We are using a NetworkManager DBUS API : https://developer.gnome.org/NetworkManager/1.26/spec.html - * */ - -// https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NM80211ApFlags -const int NM_802_11_AP_FLAGS_NONE = 0x00000000; -const int NM_802_11_AP_FLAGS_PRIVACY = 0x00000001; -const int NM_802_11_AP_FLAGS_WPS = 0x00000002; - -// https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NM80211ApSecurityFlags -const int NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001; -const int NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002; -const int NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010; -const int NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020; -const int NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100; -const int NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200; - -const QString NM_DBUS_PATH = "/org/freedesktop/NetworkManager"; -const QString NM_DBUS_PATH_SETTINGS = "/org/freedesktop/NetworkManager/Settings"; - -const QString NM_DBUS_INTERFACE = "org.freedesktop.NetworkManager"; -const QString NM_DBUS_INTERFACE_PROPERTIES = "org.freedesktop.DBus.Properties"; -const QString NM_DBUS_INTERFACE_SETTINGS = "org.freedesktop.NetworkManager.Settings"; -const QString NM_DBUS_INTERFACE_SETTINGS_CONNECTION = "org.freedesktop.NetworkManager.Settings.Connection"; -const QString NM_DBUS_INTERFACE_DEVICE = "org.freedesktop.NetworkManager.Device"; -const QString NM_DBUS_INTERFACE_DEVICE_WIRELESS = "org.freedesktop.NetworkManager.Device.Wireless"; -const QString NM_DBUS_INTERFACE_ACCESS_POINT = "org.freedesktop.NetworkManager.AccessPoint"; -const QString NM_DBUS_INTERFACE_ACTIVE_CONNECTION = "org.freedesktop.NetworkManager.Connection.Active"; -const QString NM_DBUS_INTERFACE_IP4_CONFIG = "org.freedesktop.NetworkManager.IP4Config"; - -const QString NM_DBUS_SERVICE = "org.freedesktop.NetworkManager"; - -const int NM_DEVICE_STATE_UNKNOWN = 0; -const int NM_DEVICE_STATE_ACTIVATED = 100; -const int NM_DEVICE_STATE_NEED_AUTH = 60; -const int NM_DEVICE_TYPE_WIFI = 2; -const int NM_DEVICE_TYPE_MODEM = 8; -const int NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT = 8; -const int DBUS_TIMEOUT = 100; - -// https://developer-old.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NMMetered -const int NM_METERED_UNKNOWN = 0; -const int NM_METERED_YES = 1; -const int NM_METERED_NO = 2; -const int NM_METERED_GUESS_YES = 3; -const int NM_METERED_GUESS_NO = 4; diff --git a/selfdrive/ui/qt/network/wifi_manager.cc b/selfdrive/ui/qt/network/wifi_manager.cc deleted file mode 100644 index d4ad8974b0..0000000000 --- a/selfdrive/ui/qt/network/wifi_manager.cc +++ /dev/null @@ -1,539 +0,0 @@ -#include "selfdrive/ui/qt/network/wifi_manager.h" - -#include - -#include "common/swaglog.h" -#include "selfdrive/ui/qt/util.h" - -bool compare_by_strength(const Network &a, const Network &b) { - return std::tuple(a.connected, strengthLevel(a.strength), b.ssid) > - std::tuple(b.connected, strengthLevel(b.strength), a.ssid); -} - -template -T call(const QString &path, const QString &interface, const QString &method, Args &&...args) { - QDBusInterface nm(NM_DBUS_SERVICE, path, interface, QDBusConnection::systemBus()); - nm.setTimeout(DBUS_TIMEOUT); - - QDBusMessage response = nm.call(method, std::forward(args)...); - if (response.type() == QDBusMessage::ErrorMessage) { - qCritical() << "DBus call error:" << response.errorMessage(); - return T(); - } - - if constexpr (std::is_same_v) { - return response; - } else if (response.arguments().count() >= 1) { - QVariant vFirst = response.arguments().at(0).value().variant(); - if (vFirst.canConvert()) { - return vFirst.value(); - } - QDebug critical = qCritical(); - critical << "Variant unpacking failure :" << method << ','; - (critical << ... << args); - } - return T(); -} - -template -QDBusPendingCall asyncCall(const QString &path, const QString &interface, const QString &method, Args &&...args) { - QDBusInterface nm = QDBusInterface(NM_DBUS_SERVICE, path, interface, QDBusConnection::systemBus()); - return nm.asyncCall(method, args...); -} - -bool emptyPath(const QString &path) { - return path == "" || path == "/"; -} - -WifiManager::WifiManager(QObject *parent) : QObject(parent) { - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - - // Set tethering ssid as "weedle" + first 4 characters of a dongle id - tethering_ssid = "weedle"; - if (auto dongle_id = getDongleId()) { - tethering_ssid += "-" + dongle_id->left(4); - } - - adapter = getAdapter(); - if (!adapter.isEmpty()) { - setup(); - } else { - QDBusConnection::systemBus().connect(NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "DeviceAdded", this, SLOT(deviceAdded(QDBusObjectPath))); - } - - timer.callOnTimeout(this, &WifiManager::requestScan); - - initConnections(); -} - -void WifiManager::setup() { - auto bus = QDBusConnection::systemBus(); - bus.connect(NM_DBUS_SERVICE, adapter, NM_DBUS_INTERFACE_DEVICE, "StateChanged", this, SLOT(stateChange(unsigned int, unsigned int, unsigned int))); - bus.connect(NM_DBUS_SERVICE, adapter, NM_DBUS_INTERFACE_PROPERTIES, "PropertiesChanged", this, SLOT(propertyChange(QString, QVariantMap, QStringList))); - - bus.connect(NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "ConnectionRemoved", this, SLOT(connectionRemoved(QDBusObjectPath))); - bus.connect(NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "NewConnection", this, SLOT(newConnection(QDBusObjectPath))); - - raw_adapter_state = call(adapter, NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_DEVICE, "State"); - activeAp = call(adapter, NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_DEVICE_WIRELESS, "ActiveAccessPoint").path(); - - requestScan(); -} - -void WifiManager::start() { - timer.start(5000); - refreshNetworks(); -} - -void WifiManager::stop() { - timer.stop(); -} - -void WifiManager::refreshNetworks() { - if (adapter.isEmpty() || !timer.isActive()) return; - - QDBusPendingCall pending_call = asyncCall(adapter, NM_DBUS_INTERFACE_DEVICE_WIRELESS, "GetAllAccessPoints"); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending_call); - QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &WifiManager::refreshFinished); -} - -void WifiManager::refreshFinished(QDBusPendingCallWatcher *watcher) { - ipv4_address = getIp4Address(); - seenNetworks.clear(); - - const QDBusReply> watcher_reply = *watcher; - if (!watcher_reply.isValid()) { - qCritical() << "Failed to refresh"; - watcher->deleteLater(); - return; - } - - for (const QDBusObjectPath &path : watcher_reply.value()) { - QDBusReply reply = call(path.path(), NM_DBUS_INTERFACE_PROPERTIES, "GetAll", NM_DBUS_INTERFACE_ACCESS_POINT); - if (!reply.isValid()) { - qCritical() << "Failed to retrieve properties for path:" << path.path(); - continue; - } - - auto properties = reply.value(); - const QByteArray ssid = properties["Ssid"].toByteArray(); - if (ssid.isEmpty()) continue; - - // May be multiple access points for each SSID. - // Use first for ssid and security type, then update connected status and strength using all - if (!seenNetworks.contains(ssid)) { - seenNetworks[ssid] = {ssid, 0U, ConnectedType::DISCONNECTED, getSecurityType(properties)}; - } - - if (path.path() == activeAp) { - seenNetworks[ssid].connected = (ssid == connecting_to_network) ? ConnectedType::CONNECTING : ConnectedType::CONNECTED; - } - - uint32_t strength = properties["Strength"].toUInt(); - if (seenNetworks[ssid].strength < strength) { - seenNetworks[ssid].strength = strength; - } - } - - emit refreshSignal(); - watcher->deleteLater(); -} - -QString WifiManager::getIp4Address() { - if (raw_adapter_state != NM_DEVICE_STATE_ACTIVATED) return ""; - - for (const auto &p : getActiveConnections()) { - QString type = call(p.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type"); - if (type == "802-11-wireless") { - auto ip4config = call(p.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Ip4Config"); - const auto &arr = call(ip4config.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_IP4_CONFIG, "AddressData"); - QVariantMap path; - arr.beginArray(); - while (!arr.atEnd()) { - arr >> path; - arr.endArray(); - return path.value("address").value(); - } - arr.endArray(); - } - } - return ""; -} - -SecurityType WifiManager::getSecurityType(const QVariantMap &properties) { - int sflag = properties["Flags"].toUInt(); - int wpaflag = properties["WpaFlags"].toUInt(); - int rsnflag = properties["RsnFlags"].toUInt(); - int wpa_props = wpaflag | rsnflag; - - // obtained by looking at flags of networks in the office as reported by an Android phone - const int supports_wpa = NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 | NM_802_11_AP_SEC_GROUP_WEP40 | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_KEY_MGMT_PSK; - - if ((sflag == NM_802_11_AP_FLAGS_NONE) || ((sflag & NM_802_11_AP_FLAGS_WPS) && !(wpa_props & supports_wpa))) { - return SecurityType::OPEN; - } else if ((sflag & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_props & supports_wpa) && !(wpa_props & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - return SecurityType::WPA; - } else { - LOGW("Unsupported network! sflag: %d, wpaflag: %d, rsnflag: %d", sflag, wpaflag, rsnflag); - return SecurityType::UNSUPPORTED; - } -} - -void WifiManager::connect(const Network &n, const bool is_hidden, const QString &password, const QString &username) { - setCurrentConnecting(n.ssid); - forgetConnection(n.ssid); // Clear all connections that may already exist to the network we are connecting - Connection connection; - connection["connection"]["type"] = "802-11-wireless"; - connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); - connection["connection"]["id"] = "openpilot connection " + QString::fromStdString(n.ssid.toStdString()); - connection["connection"]["autoconnect-retries"] = 0; - - connection["802-11-wireless"]["ssid"] = n.ssid; - connection["802-11-wireless"]["hidden"] = is_hidden; - connection["802-11-wireless"]["mode"] = "infrastructure"; - - if (n.security_type == SecurityType::WPA) { - connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; - connection["802-11-wireless-security"]["auth-alg"] = "open"; - connection["802-11-wireless-security"]["psk"] = password; - } - - connection["ipv4"]["method"] = "auto"; - connection["ipv4"]["dns-priority"] = 600; - connection["ipv6"]["method"] = "ignore"; - - asyncCall(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "AddConnection", QVariant::fromValue(connection)); -} - -void WifiManager::deactivateConnectionBySsid(const QString &ssid) { - for (QDBusObjectPath active_connection : getActiveConnections()) { - auto pth = call(active_connection.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "SpecificObject"); - if (!emptyPath(pth.path())) { - QString Ssid = get_property(pth.path(), "Ssid"); - if (Ssid == ssid) { - deactivateConnection(active_connection); - return; - } - } - } -} - -void WifiManager::deactivateConnection(const QDBusObjectPath &path) { - asyncCall(NM_DBUS_PATH, NM_DBUS_INTERFACE, "DeactivateConnection", QVariant::fromValue(path)); -} - -QVector WifiManager::getActiveConnections() { - auto result = call(NM_DBUS_PATH, NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE, "ActiveConnections"); - return qdbus_cast>(result); -} - -bool WifiManager::isKnownConnection(const QString &ssid) { - return !getConnectionPath(ssid).path().isEmpty(); -} - -void WifiManager::forgetConnection(const QString &ssid) { - const QDBusObjectPath &path = getConnectionPath(ssid); - if (!path.path().isEmpty()) { - call(path.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "Delete"); - } -} - -void WifiManager::setCurrentConnecting(const QString &ssid) { - connecting_to_network = ssid; - for (auto &network : seenNetworks) { - network.connected = (network.ssid == ssid) ? ConnectedType::CONNECTING : ConnectedType::DISCONNECTED; - } - emit refreshSignal(); -} - -uint WifiManager::getAdapterType(const QDBusObjectPath &path) { - return call(path.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_DEVICE, "DeviceType"); -} - -void WifiManager::requestScan() { - if (!adapter.isEmpty()) { - asyncCall(adapter, NM_DBUS_INTERFACE_DEVICE_WIRELESS, "RequestScan", QVariantMap()); - } -} - -QByteArray WifiManager::get_property(const QString &network_path , const QString &property) { - return call(network_path, NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACCESS_POINT, property); -} - -QString WifiManager::getAdapter(const uint adapter_type) { - QDBusReply> response = call(NM_DBUS_PATH, NM_DBUS_INTERFACE, "GetDevices"); - for (const QDBusObjectPath &path : response.value()) { - if (getAdapterType(path) == adapter_type) { - return path.path(); - } - } - return ""; -} - -void WifiManager::stateChange(unsigned int new_state, unsigned int previous_state, unsigned int change_reason) { - raw_adapter_state = new_state; - if (new_state == NM_DEVICE_STATE_NEED_AUTH && change_reason == NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT && !connecting_to_network.isEmpty()) { - forgetConnection(connecting_to_network); - emit wrongPassword(connecting_to_network); - } else if (new_state == NM_DEVICE_STATE_ACTIVATED) { - connecting_to_network = ""; - refreshNetworks(); - } -} - -// https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html -void WifiManager::propertyChange(const QString &interface, const QVariantMap &props, const QStringList &invalidated_props) { - if (interface == NM_DBUS_INTERFACE_DEVICE_WIRELESS && props.contains("LastScan")) { - refreshNetworks(); - } else if (interface == NM_DBUS_INTERFACE_DEVICE_WIRELESS && props.contains("ActiveAccessPoint")) { - activeAp = props.value("ActiveAccessPoint").value().path(); - } -} - -void WifiManager::deviceAdded(const QDBusObjectPath &path) { - if (getAdapterType(path) == NM_DEVICE_TYPE_WIFI && emptyPath(adapter)) { - adapter = path.path(); - setup(); - } -} - -void WifiManager::connectionRemoved(const QDBusObjectPath &path) { - knownConnections.remove(path); -} - -void WifiManager::newConnection(const QDBusObjectPath &path) { - Connection settings = getConnectionSettings(path); - if (settings.value("connection").value("type") == "802-11-wireless") { - knownConnections[path] = settings.value("802-11-wireless").value("ssid").toString(); - if (knownConnections[path] != tethering_ssid) { - activateWifiConnection(knownConnections[path]); - } - } -} - -QDBusObjectPath WifiManager::getConnectionPath(const QString &ssid) { - return knownConnections.key(ssid); -} - -Connection WifiManager::getConnectionSettings(const QDBusObjectPath &path) { - return QDBusReply(call(path.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "GetSettings")).value(); -} - -void WifiManager::initConnections() { - const QDBusReply> response = call(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "ListConnections"); - for (const QDBusObjectPath &path : response.value()) { - const Connection settings = getConnectionSettings(path); - if (settings.value("connection").value("type") == "802-11-wireless") { - knownConnections[path] = settings.value("802-11-wireless").value("ssid").toString(); - } else if (settings.value("connection").value("id") == "lte") { - lteConnectionPath = path; - } - } - - if (!isKnownConnection(tethering_ssid)) { - addTetheringConnection(); - } -} - -std::optional WifiManager::activateWifiConnection(const QString &ssid) { - const QDBusObjectPath &path = getConnectionPath(ssid); - if (!path.path().isEmpty()) { - setCurrentConnecting(ssid); - return asyncCall(NM_DBUS_PATH, NM_DBUS_INTERFACE, "ActivateConnection", QVariant::fromValue(path), QVariant::fromValue(QDBusObjectPath(adapter)), QVariant::fromValue(QDBusObjectPath("/"))); - } - return std::nullopt; -} - -void WifiManager::activateModemConnection(const QDBusObjectPath &path) { - QString modem = getAdapter(NM_DEVICE_TYPE_MODEM); - if (!path.path().isEmpty() && !modem.isEmpty()) { - asyncCall(NM_DBUS_PATH, NM_DBUS_INTERFACE, "ActivateConnection", QVariant::fromValue(path), QVariant::fromValue(QDBusObjectPath(modem)), QVariant::fromValue(QDBusObjectPath("/"))); - } -} - -// function matches tici/hardware.py -// FIXME: it can mistakenly show CELL when connected to WIFI -NetworkType WifiManager::currentNetworkType() { - auto primary_conn = call(NM_DBUS_PATH, NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE, "PrimaryConnection"); - auto primary_type = call(primary_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type"); - - if (primary_type == "802-3-ethernet") { - return NetworkType::ETHERNET; - } else if (primary_type == "802-11-wireless" && !isTetheringEnabled()) { - return NetworkType::WIFI; - } else { - for (const QDBusObjectPath &conn : getActiveConnections()) { - auto type = call(conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type"); - if (type == "gsm") { - return NetworkType::CELL; - } - } - } - return NetworkType::NONE; -} - -MeteredType WifiManager::currentNetworkMetered() { - MeteredType metered = MeteredType::UNKNOWN; - for (const auto &active_conn : getActiveConnections()) { - QString type = call(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type"); - if (type == "802-11-wireless") { - QDBusObjectPath conn = call(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Connection"); - if (!conn.path().isEmpty()) { - Connection settings = getConnectionSettings(conn); - int metered_prop = settings.value("connection").value("metered").toInt(); - if (metered_prop == NM_METERED_YES) { - metered = MeteredType::YES; - } else if (metered_prop == NM_METERED_NO) { - metered = MeteredType::NO; - } - } - break; - } - } - return metered; -} - -std::optional WifiManager::setCurrentNetworkMetered(MeteredType metered) { - for (const auto &active_conn : getActiveConnections()) { - QString type = call(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type"); - if (type == "802-11-wireless") { - if (!isTetheringEnabled()) { - QDBusObjectPath conn = call(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Connection"); - if (!conn.path().isEmpty()) { - Connection settings = getConnectionSettings(conn); - settings["connection"]["metered"] = static_cast(metered); - return asyncCall(conn.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "Update", QVariant::fromValue(settings)); - } - } - } - } - return std::nullopt; -} - -void WifiManager::updateGsmSettings(bool roaming, QString apn, bool metered) { - if (!lteConnectionPath.path().isEmpty()) { - bool changes = false; - bool auto_config = apn.isEmpty(); - Connection settings = getConnectionSettings(lteConnectionPath); - if (settings.value("gsm").value("auto-config").toBool() != auto_config) { - qWarning() << "Changing gsm.auto-config to" << auto_config; - settings["gsm"]["auto-config"] = auto_config; - changes = true; - } - - if (settings.value("gsm").value("apn").toString() != apn) { - qWarning() << "Changing gsm.apn to" << apn; - settings["gsm"]["apn"] = apn; - changes = true; - } - - if (settings.value("gsm").value("home-only").toBool() == roaming) { - qWarning() << "Changing gsm.home-only to" << !roaming; - settings["gsm"]["home-only"] = !roaming; - changes = true; - } - - int meteredInt = metered ? NM_METERED_UNKNOWN : NM_METERED_NO; - if (settings.value("connection").value("metered").toInt() != meteredInt) { - qWarning() << "Changing connection.metered to" << meteredInt; - settings["connection"]["metered"] = meteredInt; - changes = true; - } - - if (changes) { - QDBusPendingCall pending_call = asyncCall(lteConnectionPath.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "UpdateUnsaved", QVariant::fromValue(settings)); // update is temporary - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending_call); - QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher]() { - deactivateConnection(lteConnectionPath); - activateModemConnection(lteConnectionPath); - watcher->deleteLater(); - }); - } - } -} - -// Functions for tethering -void WifiManager::addTetheringConnection() { - Connection connection; - connection["connection"]["id"] = "Hotspot"; - connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); - connection["connection"]["type"] = "802-11-wireless"; - connection["connection"]["interface-name"] = "wlan0"; - connection["connection"]["autoconnect"] = false; - - connection["802-11-wireless"]["band"] = "bg"; - connection["802-11-wireless"]["mode"] = "ap"; - connection["802-11-wireless"]["ssid"] = tethering_ssid.toUtf8(); - - connection["802-11-wireless-security"]["group"] = QStringList("ccmp"); - connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; - connection["802-11-wireless-security"]["pairwise"] = QStringList("ccmp"); - connection["802-11-wireless-security"]["proto"] = QStringList("rsn"); - connection["802-11-wireless-security"]["psk"] = defaultTetheringPassword; - - connection["ipv4"]["method"] = "shared"; - QVariantMap address; - address["address"] = "192.168.43.1"; - address["prefix"] = 24u; - connection["ipv4"]["address-data"] = QVariant::fromValue(IpConfig() << address); - connection["ipv4"]["gateway"] = "192.168.43.1"; - connection["ipv4"]["never-default"] = true; - connection["ipv6"]["method"] = "ignore"; - - asyncCall(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "AddConnection", QVariant::fromValue(connection)); -} - -void WifiManager::tetheringActivated(QDBusPendingCallWatcher *call) { - if (!ipv4_forward) { - QTimer::singleShot(5000, this, [=] { - qWarning() << "net.ipv4.ip_forward = 0"; - std::system("sudo sysctl net.ipv4.ip_forward=0"); - }); - } - call->deleteLater(); - tethering_on = true; -} - -void WifiManager::setTetheringEnabled(bool enabled) { - if (enabled) { - auto pending_call = activateWifiConnection(tethering_ssid); - - if (pending_call) { - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(*pending_call); - QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &WifiManager::tetheringActivated); - } - - } else { - deactivateConnectionBySsid(tethering_ssid); - tethering_on = false; - } -} - -bool WifiManager::isTetheringEnabled() { - if (!emptyPath(activeAp)) { - return get_property(activeAp, "Ssid") == tethering_ssid; - } - return false; -} - -QString WifiManager::getTetheringPassword() { - const QDBusObjectPath &path = getConnectionPath(tethering_ssid); - if (!path.path().isEmpty()) { - QDBusReply> response = call(path.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "GetSecrets", "802-11-wireless-security"); - return response.value().value("802-11-wireless-security").value("psk").toString(); - } - return ""; -} - -void WifiManager::changeTetheringPassword(const QString &newPassword) { - const QDBusObjectPath &path = getConnectionPath(tethering_ssid); - if (!path.path().isEmpty()) { - Connection settings = getConnectionSettings(path); - settings["802-11-wireless-security"]["psk"] = newPassword; - call(path.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "Update", QVariant::fromValue(settings)); - if (isTetheringEnabled()) { - activateWifiConnection(tethering_ssid); - } - } -} diff --git a/selfdrive/ui/qt/network/wifi_manager.h b/selfdrive/ui/qt/network/wifi_manager.h deleted file mode 100644 index cab932a388..0000000000 --- a/selfdrive/ui/qt/network/wifi_manager.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "selfdrive/ui/qt/network/networkmanager.h" - -enum class SecurityType { - OPEN, - WPA, - UNSUPPORTED -}; -enum class ConnectedType { - DISCONNECTED, - CONNECTING, - CONNECTED -}; -enum class NetworkType { - NONE, - WIFI, - CELL, - ETHERNET -}; -enum class MeteredType { - UNKNOWN, - YES, - NO -}; - -typedef QMap Connection; -typedef QVector IpConfig; - -struct Network { - QByteArray ssid; - unsigned int strength; - ConnectedType connected; - SecurityType security_type; -}; -bool compare_by_strength(const Network &a, const Network &b); -inline int strengthLevel(unsigned int strength) { return std::clamp((int)round(strength / 33.), 0, 3); } - -class WifiManager : public QObject { - Q_OBJECT - -public: - QMap seenNetworks; - QMap knownConnections; - QString ipv4_address; - bool tethering_on = false; - bool ipv4_forward = false; - - explicit WifiManager(QObject* parent); - void start(); - void stop(); - void requestScan(); - void forgetConnection(const QString &ssid); - bool isKnownConnection(const QString &ssid); - std::optional activateWifiConnection(const QString &ssid); - NetworkType currentNetworkType(); - MeteredType currentNetworkMetered(); - std::optional setCurrentNetworkMetered(MeteredType metered); - void updateGsmSettings(bool roaming, QString apn, bool metered); - void connect(const Network &ssid, const bool is_hidden = false, const QString &password = {}, const QString &username = {}); - - // Tethering functions - void setTetheringEnabled(bool enabled); - bool isTetheringEnabled(); - void changeTetheringPassword(const QString &newPassword); - QString getTetheringPassword(); - -private: - QString adapter; // Path to network manager wifi-device - QTimer timer; - unsigned int raw_adapter_state = NM_DEVICE_STATE_UNKNOWN; // Connection status https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NMDeviceState - QString connecting_to_network; - QString tethering_ssid; - const QString defaultTetheringPassword = "swagswagcomma"; - QString activeAp; - QDBusObjectPath lteConnectionPath; - - QString getAdapter(const uint = NM_DEVICE_TYPE_WIFI); - uint getAdapterType(const QDBusObjectPath &path); - QString getIp4Address(); - void deactivateConnectionBySsid(const QString &ssid); - void deactivateConnection(const QDBusObjectPath &path); - QVector getActiveConnections(); - QByteArray get_property(const QString &network_path, const QString &property); - SecurityType getSecurityType(const QVariantMap &properties); - QDBusObjectPath getConnectionPath(const QString &ssid); - Connection getConnectionSettings(const QDBusObjectPath &path); - void initConnections(); - void setup(); - void refreshNetworks(); - void activateModemConnection(const QDBusObjectPath &path); - void addTetheringConnection(); - void setCurrentConnecting(const QString &ssid); - -signals: - void wrongPassword(const QString &ssid); - void refreshSignal(); - -private slots: - void stateChange(unsigned int new_state, unsigned int previous_state, unsigned int change_reason); - void propertyChange(const QString &interface, const QVariantMap &props, const QStringList &invalidated_props); - void deviceAdded(const QDBusObjectPath &path); - void connectionRemoved(const QDBusObjectPath &path); - void newConnection(const QDBusObjectPath &path); - void refreshFinished(QDBusPendingCallWatcher *call); - void tetheringActivated(QDBusPendingCallWatcher *call); -}; diff --git a/selfdrive/ui/qt/offroad/developer_panel.cc b/selfdrive/ui/qt/offroad/developer_panel.cc deleted file mode 100644 index a095228da2..0000000000 --- a/selfdrive/ui/qt/offroad/developer_panel.cc +++ /dev/null @@ -1,95 +0,0 @@ -#include "selfdrive/ui/qt/offroad/developer_panel.h" -#include "selfdrive/ui/qt/widgets/ssh_keys.h" -#include "selfdrive/ui/qt/widgets/controls.h" - -DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) { - adbToggle = new ParamControl("AdbEnabled", tr("Enable ADB"), - tr("ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info."), ""); - addItem(adbToggle); - - // SSH keys - addItem(new SshToggle()); - addItem(new SshControl()); - - joystickToggle = new ParamControl("JoystickDebugMode", tr("Joystick Debug Mode"), "", ""); - QObject::connect(joystickToggle, &ParamControl::toggleFlipped, [=](bool state) { - params.putBool("LongitudinalManeuverMode", false); - longManeuverToggle->refresh(); - }); - addItem(joystickToggle); - - longManeuverToggle = new ParamControl("LongitudinalManeuverMode", tr("Longitudinal Maneuver Mode"), "", ""); - QObject::connect(longManeuverToggle, &ParamControl::toggleFlipped, [=](bool state) { - params.putBool("JoystickDebugMode", false); - joystickToggle->refresh(); - }); - addItem(longManeuverToggle); - - experimentalLongitudinalToggle = new ParamControl( - "AlphaLongitudinalEnabled", - tr("openpilot Longitudinal Control (Alpha)"), - QString("%1

%2") - .arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).")) - .arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. " - "Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")), - "" - ); - experimentalLongitudinalToggle->setConfirmation(true, false); - QObject::connect(experimentalLongitudinalToggle, &ParamControl::toggleFlipped, [=]() { - updateToggles(offroad); - }); - addItem(experimentalLongitudinalToggle); - - // Joystick and longitudinal maneuvers should be hidden on release branches - is_release = params.getBool("IsReleaseBranch"); - - // Toggles should be not available to change in onroad state - QObject::connect(uiState(), &UIState::offroadTransition, this, &DeveloperPanel::updateToggles); -} - -void DeveloperPanel::updateToggles(bool _offroad) { - for (auto btn : findChildren()) { - btn->setVisible(!is_release); - - /* - * experimentalLongitudinalToggle should be toggelable when: - * - visible, and - * - during onroad & offroad states - */ - if (btn != experimentalLongitudinalToggle) { - btn->setEnabled(_offroad); - } - } - - // longManeuverToggle and experimentalLongitudinalToggle should not be toggleable if the car does not have longitudinal control - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - if (!CP.getAlphaLongitudinalAvailable() || is_release) { - params.remove("AlphaLongitudinalEnabled"); - experimentalLongitudinalToggle->setEnabled(false); - } - - /* - * experimentalLongitudinalToggle should be visible when: - * - is not a release branch, and - * - the car supports experimental longitudinal control (alpha) - */ - experimentalLongitudinalToggle->setVisible(CP.getAlphaLongitudinalAvailable() && !is_release); - - longManeuverToggle->setEnabled(hasLongitudinalControl(CP) && _offroad); - } else { - longManeuverToggle->setEnabled(false); - experimentalLongitudinalToggle->setVisible(false); - } - experimentalLongitudinalToggle->refresh(); - - offroad = _offroad; -} - -void DeveloperPanel::showEvent(QShowEvent *event) { - updateToggles(offroad); -} diff --git a/selfdrive/ui/qt/offroad/developer_panel.h b/selfdrive/ui/qt/offroad/developer_panel.h deleted file mode 100644 index c73421b185..0000000000 --- a/selfdrive/ui/qt/offroad/developer_panel.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/offroad/settings.h" - -class DeveloperPanel : public ListWidget { - Q_OBJECT -public: - explicit DeveloperPanel(SettingsWindow *parent); - void showEvent(QShowEvent *event) override; - -private: - Params params; - ParamControl* adbToggle; - ParamControl* joystickToggle; - ParamControl* longManeuverToggle; - ParamControl* experimentalLongitudinalToggle; - bool is_release; - bool offroad = false; - -private slots: - void updateToggles(bool _offroad); -}; diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc deleted file mode 100644 index 9010227f18..0000000000 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "selfdrive/ui/qt/offroad/driverview.h" - -#include -#include - -#include "selfdrive/ui/qt/util.h" - -DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraWidget("camerad", VISION_STREAM_DRIVER, parent) { - QObject::connect(this, &CameraWidget::clicked, this, &DriverViewWindow::done); - QObject::connect(device(), &Device::interactiveTimeout, this, [this]() { - if (isVisible()) { - emit done(); - } - }); -} - -void DriverViewWindow::showEvent(QShowEvent* event) { - params.putBool("IsDriverViewEnabled", true); - device()->resetInteractiveTimeout(60); - CameraWidget::showEvent(event); -} - -void DriverViewWindow::hideEvent(QHideEvent* event) { - params.putBool("IsDriverViewEnabled", false); - stopVipcThread(); - CameraWidget::hideEvent(event); -} - -void DriverViewWindow::paintGL() { - CameraWidget::paintGL(); - - std::lock_guard lk(frame_lock); - QPainter p(this); - // startup msg - if (frames.empty()) { - p.setPen(Qt::white); - p.setRenderHint(QPainter::TextAntialiasing); - p.setFont(InterFont(100, QFont::Bold)); - p.drawText(geometry(), Qt::AlignCenter, tr("camera starting")); - return; - } - - const auto &sm = *(uiState()->sm); - cereal::DriverStateV2::Reader driver_state = sm["driverStateV2"].getDriverStateV2(); - bool is_rhd = driver_state.getWheelOnRightProb() > 0.5; - auto driver_data = is_rhd ? driver_state.getRightDriverData() : driver_state.getLeftDriverData(); - - bool face_detected = driver_data.getFaceProb() > 0.7; - if (face_detected) { - auto fxy_list = driver_data.getFacePosition(); - auto std_list = driver_data.getFaceOrientationStd(); - float face_x = fxy_list[0]; - float face_y = fxy_list[1]; - float face_std = std::max(std_list[0], std_list[1]); - - float alpha = 0.7; - if (face_std > 0.15) { - alpha = std::max(0.7 - (face_std-0.15)*3.5, 0.0); - } - const int box_size = 220; - // use approx instead of distort_points - int fbox_x = 1080.0 - 1714.0 * face_x; - int fbox_y = -135.0 + (504.0 + std::abs(face_x)*112.0) + (1205.0 - std::abs(face_x)*724.0) * face_y; - p.setPen(QPen(QColor(255, 255, 255, alpha * 255), 10)); - p.drawRoundedRect(fbox_x - box_size / 2, fbox_y - box_size / 2, box_size, box_size, 35.0, 35.0); - } - - driver_monitor.updateState(*uiState()); - driver_monitor.draw(p, rect()); -} - -mat4 DriverViewWindow::calcFrameMatrix() { - const float driver_view_ratio = 2.0; - const float yscale = stream_height * driver_view_ratio / stream_width; - const float xscale = yscale * glHeight() / glWidth() * stream_width / stream_height; - return mat4{{ - xscale, 0.0, 0.0, 0.0, - 0.0, yscale, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; -} diff --git a/selfdrive/ui/qt/offroad/driverview.h b/selfdrive/ui/qt/offroad/driverview.h deleted file mode 100644 index f6eb752fe6..0000000000 --- a/selfdrive/ui/qt/offroad/driverview.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/widgets/cameraview.h" -#include "selfdrive/ui/qt/onroad/driver_monitoring.h" - -class DriverViewWindow : public CameraWidget { - Q_OBJECT - -public: - explicit DriverViewWindow(QWidget *parent); - -signals: - void done(); - -protected: - mat4 calcFrameMatrix() override; - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - void paintGL() override; - - Params params; - DriverMonitorRenderer driver_monitor; -}; diff --git a/selfdrive/ui/qt/offroad/experimental_mode.cc b/selfdrive/ui/qt/offroad/experimental_mode.cc deleted file mode 100644 index e255073f39..0000000000 --- a/selfdrive/ui/qt/offroad/experimental_mode.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include "selfdrive/ui/qt/offroad/experimental_mode.h" - -#include -#include -#include -#include -#include - -#include "selfdrive/ui/ui.h" - -ExperimentalModeButton::ExperimentalModeButton(QWidget *parent) : QPushButton(parent) { - chill_pixmap = QPixmap("../assets/icons/couch.svg").scaledToWidth(img_width, Qt::SmoothTransformation); - experimental_pixmap = QPixmap("../assets/icons/experimental_grey.svg").scaledToWidth(img_width, Qt::SmoothTransformation); - - // go to toggles and expand experimental mode description - connect(this, &QPushButton::clicked, [=]() { emit openSettings(2, "ExperimentalMode"); }); - - setFixedHeight(125); - QHBoxLayout *main_layout = new QHBoxLayout; - main_layout->setContentsMargins(horizontal_padding, 0, horizontal_padding, 0); - - mode_label = new QLabel; - mode_icon = new QLabel; - mode_icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - - main_layout->addWidget(mode_label, 1, Qt::AlignLeft); - main_layout->addWidget(mode_icon, 0, Qt::AlignRight); - - setLayout(main_layout); - - setStyleSheet(R"( - QPushButton { - border: none; - } - - QLabel { - font-size: 45px; - font-weight: 300; - text-align: left; - font-family: JetBrainsMono; - color: #000000; - } - )"); -} - -void ExperimentalModeButton::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing); - - QPainterPath path; - path.addRoundedRect(rect(), 10, 10); - - // gradient - bool pressed = isDown(); - QLinearGradient gradient(rect().left(), 0, rect().right(), 0); - if (experimental_mode) { - gradient.setColorAt(0, QColor(255, 155, 63, pressed ? 0xcc : 0xff)); - gradient.setColorAt(1, QColor(219, 56, 34, pressed ? 0xcc : 0xff)); - } else { - gradient.setColorAt(0, QColor(20, 255, 171, pressed ? 0xcc : 0xff)); - gradient.setColorAt(1, QColor(35, 149, 255, pressed ? 0xcc : 0xff)); - } - p.fillPath(path, gradient); - - // vertical line - p.setPen(QPen(QColor(0, 0, 0, 0x4d), 3, Qt::SolidLine)); - int line_x = rect().right() - img_width - (2 * horizontal_padding); - p.drawLine(line_x, rect().bottom(), line_x, rect().top()); -} - -void ExperimentalModeButton::showEvent(QShowEvent *event) { - experimental_mode = params.getBool("ExperimentalMode"); - mode_icon->setPixmap(experimental_mode ? experimental_pixmap : chill_pixmap); - mode_label->setText(experimental_mode ? tr("EXPERIMENTAL MODE ON") : tr("CHILL MODE ON")); -} diff --git a/selfdrive/ui/qt/offroad/experimental_mode.h b/selfdrive/ui/qt/offroad/experimental_mode.h deleted file mode 100644 index bfb7638bbe..0000000000 --- a/selfdrive/ui/qt/offroad/experimental_mode.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -#include "common/params.h" - -class ExperimentalModeButton : public QPushButton { - Q_OBJECT - -public: - explicit ExperimentalModeButton(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString &toggle = ""); - -private: - void showEvent(QShowEvent *event) override; - - Params params; - bool experimental_mode; - int img_width = 100; - int horizontal_padding = 30; - QPixmap experimental_pixmap; - QPixmap chill_pixmap; - QLabel *mode_label; - QLabel *mode_icon; - -protected: - void paintEvent(QPaintEvent *event) override; -}; diff --git a/selfdrive/ui/qt/offroad/firehose.cc b/selfdrive/ui/qt/offroad/firehose.cc deleted file mode 100644 index aa158b4c7b..0000000000 --- a/selfdrive/ui/qt/offroad/firehose.cc +++ /dev/null @@ -1,112 +0,0 @@ -#include "selfdrive/ui/qt/offroad/firehose.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/offroad/settings.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent) { - layout = new QVBoxLayout(this); - layout->setContentsMargins(40, 40, 40, 40); - layout->setSpacing(20); - - // header - QLabel *title = new QLabel(tr("Firehose Mode")); - title->setStyleSheet("font-size: 100px; font-weight: 500; font-family: 'Noto Color Emoji';"); - layout->addWidget(title, 0, Qt::AlignCenter); - - // Create a container for the content - QFrame *content = new QFrame(); - content->setStyleSheet("background-color: #292929; border-radius: 15px; padding: 20px;"); - QVBoxLayout *content_layout = new QVBoxLayout(content); - content_layout->setSpacing(20); - - // Top description - QLabel *description = new QLabel(tr("openpilot learns to drive by watching humans, like you, drive.\n\nFirehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.")); - description->setStyleSheet("font-size: 45px; padding-bottom: 20px;"); - description->setWordWrap(true); - content_layout->addWidget(description); - - // Add a separator - QFrame *line = new QFrame(); - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - line->setStyleSheet("background-color: #444444; margin-top: 5px; margin-bottom: 5px;"); - content_layout->addWidget(line); - - toggle_label = new QLabel(tr("Firehose Mode: ACTIVE")); - toggle_label->setStyleSheet("font-size: 60px; font-weight: bold; color: white;"); - content_layout->addWidget(toggle_label); - - // Add contribution label - contribution_label = new QLabel(); - contribution_label->setStyleSheet("font-size: 52px; margin-top: 10px; margin-bottom: 10px;"); - contribution_label->setWordWrap(true); - contribution_label->hide(); - content_layout->addWidget(contribution_label); - - // Add a separator before detailed instructions - QFrame *line2 = new QFrame(); - line2->setFrameShape(QFrame::HLine); - line2->setFrameShadow(QFrame::Sunken); - line2->setStyleSheet("background-color: #444444; margin-top: 10px; margin-bottom: 10px;"); - content_layout->addWidget(line2); - - // Detailed instructions at the bottom - detailed_instructions = new QLabel(tr( - "For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.
" - "
" - "Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.
" - "

" - "Frequently Asked Questions

" - "Does it matter how or where I drive? Nope, just drive as you normally would.

" - "Do all of my segments get pulled in Firehose Mode? No, we selectively pull a subset of your segments.

" - "What's a good USB-C adapter? Any fast phone or laptop charger should be fine.

" - "Does it matter which software I run? Yes, only upstream openpilot (and particular forks) are able to be used for training." - )); - detailed_instructions->setStyleSheet("font-size: 40px; color: #E4E4E4;"); - detailed_instructions->setWordWrap(true); - content_layout->addWidget(detailed_instructions); - - layout->addWidget(content, 1); - - // Set up the API request for firehose stats - const QString dongle_id = QString::fromStdString(Params().get("DongleId")); - firehose_stats = new RequestRepeater(this, CommaApi::BASE_URL + "/v1/devices/" + dongle_id + "/firehose_stats", - "ApiCache_FirehoseStats", 30, true); - QObject::connect(firehose_stats, &RequestRepeater::requestDone, [=](const QString &response, bool success) { - if (success) { - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - QJsonObject json = doc.object(); - int count = json["firehose"].toInt(); - contribution_label->setText(tr("%n segment(s) of your driving is in the training dataset so far.", "", count)); - contribution_label->show(); - } - }); - - QObject::connect(uiState(), &UIState::uiUpdate, this, &FirehosePanel::refresh); -} - -void FirehosePanel::refresh() { - auto deviceState = (*uiState()->sm)["deviceState"].getDeviceState(); - auto networkType = deviceState.getNetworkType(); - bool networkMetered = deviceState.getNetworkMetered(); - - bool is_active = !networkMetered && (networkType != cereal::DeviceState::NetworkType::NONE); - if (is_active) { - toggle_label->setText(tr("ACTIVE")); - toggle_label->setStyleSheet("font-size: 60px; font-weight: bold; color: #2ecc71;"); - } else { - toggle_label->setText(tr("INACTIVE: connect to an unmetered network")); - toggle_label->setStyleSheet("font-size: 60px;"); - } -} diff --git a/selfdrive/ui/qt/offroad/firehose.h b/selfdrive/ui/qt/offroad/firehose.h deleted file mode 100644 index 9082cb0f99..0000000000 --- a/selfdrive/ui/qt/offroad/firehose.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include -#include -#include "selfdrive/ui/qt/request_repeater.h" - -// Forward declarations -class SettingsWindow; - -class FirehosePanel : public QWidget { - Q_OBJECT -public: - explicit FirehosePanel(SettingsWindow *parent); - -private: - QVBoxLayout *layout; - - QLabel *detailed_instructions; - QLabel *contribution_label; - QLabel *toggle_label; - - RequestRepeater *firehose_stats; - -private slots: - void refresh(); -}; diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc deleted file mode 100644 index 1390566671..0000000000 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ /dev/null @@ -1,211 +0,0 @@ -#include "selfdrive/ui/qt/offroad/onboarding.h" - -#include - -#include -#include -#include -#include - -#include "common/util.h" -#include "common/params.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/input.h" - -TrainingGuide::TrainingGuide(QWidget *parent) : QFrame(parent) { - setAttribute(Qt::WA_OpaquePaintEvent); -} - -void TrainingGuide::mouseReleaseEvent(QMouseEvent *e) { - if (click_timer.elapsed() < 250) { - return; - } - click_timer.restart(); - - auto contains = [this](QRect r, const QPoint &pt) { - if (image.size() != image_raw_size) { - QTransform transform; - transform.translate((width()- image.width()) / 2.0, (height()- image.height()) / 2.0); - transform.scale(image.width() / (float)image_raw_size.width(), image.height() / (float)image_raw_size.height()); - r= transform.mapRect(r); - } - return r.contains(pt); - }; - - if (contains(boundingRect[currentIndex], e->pos())) { - if (currentIndex == 9) { - const QRect yes = QRect(707, 804, 531, 164); - Params().putBool("RecordFront", contains(yes, e->pos())); - } - currentIndex += 1; - } else if (currentIndex == (boundingRect.size() - 2) && contains(boundingRect.last(), e->pos())) { - currentIndex = 0; - } - - if (currentIndex >= (boundingRect.size() - 1)) { - emit completedTraining(); - } else { - update(); - } -} - -void TrainingGuide::showEvent(QShowEvent *event) { - currentIndex = 0; - click_timer.start(); -} - -QImage TrainingGuide::loadImage(int id) { - QImage img(img_path + QString("step%1.png").arg(id)); - image_raw_size = img.size(); - if (image_raw_size != rect().size()) { - img = img.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); - } - return img; -} - -void TrainingGuide::paintEvent(QPaintEvent *event) { - QPainter painter(this); - - QRect bg(0, 0, painter.device()->width(), painter.device()->height()); - painter.fillRect(bg, QColor("#000000")); - - image = loadImage(currentIndex); - QRect rect(image.rect()); - rect.moveCenter(bg.center()); - painter.drawImage(rect.topLeft(), image); - - // progress bar - if (currentIndex > 0 && currentIndex < (boundingRect.size() - 2)) { - const int h = 20; - const int w = (currentIndex / (float)(boundingRect.size() - 2)) * width(); - painter.fillRect(QRect(0, height() - h, w, h), QColor("#465BEA")); - } -} - -void TermsPage::showEvent(QShowEvent *event) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(45, 35, 45, 45); - main_layout->setSpacing(0); - - QVBoxLayout *vlayout = new QVBoxLayout(); - vlayout->setContentsMargins(165, 165, 165, 0); - main_layout->addLayout(vlayout); - - QLabel *title = new QLabel(tr("Welcome to openpilot")); - title->setStyleSheet("font-size: 90px; font-weight: 500;"); - vlayout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft); - - vlayout->addSpacing(90); - QLabel *desc = new QLabel(tr("You must accept the Terms and Conditions to use openpilot. Read the latest terms at https://comma.ai/terms before continuing.")); - desc->setWordWrap(true); - desc->setStyleSheet("font-size: 80px; font-weight: 300;"); - vlayout->addWidget(desc, 0); - - vlayout->addStretch(); - - QHBoxLayout* buttons = new QHBoxLayout; - buttons->setMargin(0); - buttons->setSpacing(45); - main_layout->addLayout(buttons); - - QPushButton *decline_btn = new QPushButton(tr("Decline")); - buttons->addWidget(decline_btn); - QObject::connect(decline_btn, &QPushButton::clicked, this, &TermsPage::declinedTerms); - - accept_btn = new QPushButton(tr("Agree")); - accept_btn->setStyleSheet(R"( - QPushButton { - background-color: #465BEA; - } - QPushButton:pressed { - background-color: #3049F4; - } - )"); - buttons->addWidget(accept_btn); - QObject::connect(accept_btn, &QPushButton::clicked, this, &TermsPage::acceptedTerms); -} - -void DeclinePage::showEvent(QShowEvent *event) { - if (layout()) { - return; - } - - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(45); - main_layout->setSpacing(40); - - QLabel *text = new QLabel(this); - text->setText(tr("You must accept the Terms and Conditions in order to use openpilot.")); - text->setStyleSheet(R"(font-size: 80px; font-weight: 300; margin: 200px;)"); - text->setWordWrap(true); - main_layout->addWidget(text, 0, Qt::AlignCenter); - - QHBoxLayout* buttons = new QHBoxLayout; - buttons->setSpacing(45); - main_layout->addLayout(buttons); - - QPushButton *back_btn = new QPushButton(tr("Back")); - buttons->addWidget(back_btn); - - QObject::connect(back_btn, &QPushButton::clicked, this, &DeclinePage::getBack); - - QPushButton *uninstall_btn = new QPushButton(tr("Decline, uninstall %1").arg(getBrand())); - uninstall_btn->setStyleSheet("background-color: #B73D3D"); - buttons->addWidget(uninstall_btn); - QObject::connect(uninstall_btn, &QPushButton::clicked, [=]() { - Params().putBool("DoUninstall", true); - }); -} - -void OnboardingWindow::updateActiveScreen() { - if (!accepted_terms) { - setCurrentIndex(0); - } else if (!training_done) { - setCurrentIndex(1); - } else { - emit onboardingDone(); - } -} - -OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { - std::string current_terms_version = params.get("TermsVersion"); - std::string current_training_version = params.get("TrainingVersion"); - accepted_terms = params.get("HasAcceptedTerms") == current_terms_version; - training_done = params.get("CompletedTrainingVersion") == current_training_version; - - TermsPage* terms = new TermsPage(this); - addWidget(terms); - connect(terms, &TermsPage::acceptedTerms, [=]() { - params.put("HasAcceptedTerms", current_terms_version); - accepted_terms = true; - updateActiveScreen(); - }); - connect(terms, &TermsPage::declinedTerms, [=]() { setCurrentIndex(2); }); - - TrainingGuide* tr = new TrainingGuide(this); - addWidget(tr); - connect(tr, &TrainingGuide::completedTraining, [=]() { - training_done = true; - params.put("CompletedTrainingVersion", current_training_version); - updateActiveScreen(); - }); - - DeclinePage* declinePage = new DeclinePage(this); - addWidget(declinePage); - connect(declinePage, &DeclinePage::getBack, [=]() { updateActiveScreen(); }); - - setStyleSheet(R"( - * { - color: white; - background-color: black; - } - QPushButton { - height: 160px; - font-size: 55px; - font-weight: 400; - border-radius: 10px; - background-color: #4F4F4F; - } - )"); - updateActiveScreen(); -} diff --git a/selfdrive/ui/qt/offroad/onboarding.h b/selfdrive/ui/qt/offroad/onboarding.h deleted file mode 100644 index db229c5fa6..0000000000 --- a/selfdrive/ui/qt/offroad/onboarding.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/qt_window.h" - -class TrainingGuide : public QFrame { - Q_OBJECT - -public: - explicit TrainingGuide(QWidget *parent = 0); - -private: - void showEvent(QShowEvent *event) override; - void paintEvent(QPaintEvent *event) override; - void mouseReleaseEvent(QMouseEvent* e) override; - QImage loadImage(int id); - - QImage image; - QSize image_raw_size; - int currentIndex = 0; - - // Bounding boxes for each training guide step - const QRect continueBtn = {1840, 0, 320, 1080}; - QVector boundingRect { - QRect(112, 804, 618, 164), - continueBtn, - continueBtn, - QRect(1641, 558, 210, 313), - QRect(1662, 528, 184, 108), - continueBtn, - QRect(1814, 621, 211, 170), - QRect(1350, 0, 497, 755), - QRect(1540, 386, 468, 238), - QRect(112, 804, 1126, 164), - QRect(1598, 199, 316, 333), - continueBtn, - QRect(1364, 90, 796, 990), - continueBtn, - QRect(1593, 114, 318, 853), - QRect(1379, 511, 391, 243), - continueBtn, - continueBtn, - QRect(630, 804, 626, 164), - QRect(108, 804, 426, 164), - }; - - const QString img_path = "../assets/training/"; - QElapsedTimer click_timer; - -signals: - void completedTraining(); -}; - - -class TermsPage : public QFrame { - Q_OBJECT - -public: - explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {} - -private: - void showEvent(QShowEvent *event) override; - - QPushButton *accept_btn; - -signals: - void acceptedTerms(); - void declinedTerms(); -}; - -class DeclinePage : public QFrame { - Q_OBJECT - -public: - explicit DeclinePage(QWidget *parent = 0) : QFrame(parent) {} - -private: - void showEvent(QShowEvent *event) override; - -signals: - void getBack(); -}; - -class OnboardingWindow : public QStackedWidget { - Q_OBJECT - -public: - explicit OnboardingWindow(QWidget *parent = 0); - inline void showTrainingGuide() { setCurrentIndex(1); } - inline bool completed() const { return accepted_terms && training_done; } - -private: - void updateActiveScreen(); - - Params params; - bool accepted_terms = false, training_done = false; - -signals: - void onboardingDone(); -}; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc deleted file mode 100644 index 6eb8693a1a..0000000000 --- a/selfdrive/ui/qt/offroad/settings.cc +++ /dev/null @@ -1,535 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "common/util.h" -#include "selfdrive/ui/qt/network/networking.h" -#include "selfdrive/ui/qt/offroad/settings.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/widgets/prime.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" -#include "selfdrive/ui/qt/offroad/developer_panel.h" -#include "selfdrive/ui/qt/offroad/firehose.h" - -TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { - // param, title, desc, icon, restart needed - std::vector> toggle_defs{ - { - "OpenpilotEnabledToggle", - tr("Enable openpilot"), - tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature."), - "../assets/icons/chffr_wheel.png", - true, - }, - { - "ExperimentalMode", - tr("Experimental Mode"), - "", - "../assets/icons/experimental_white.svg", - false, - }, - { - "DisengageOnAccelerator", - tr("Disengage on Accelerator Pedal"), - tr("When enabled, pressing the accelerator pedal will disengage openpilot."), - "../assets/icons/disengage_on_accelerator.svg", - false, - }, - { - "IsLdwEnabled", - tr("Enable Lane Departure Warnings"), - tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), - "../assets/icons/warning.png", - false, - }, - { - "AlwaysOnDM", - tr("Always-On Driver Monitoring"), - tr("Enable driver monitoring even when openpilot is not engaged."), - "../assets/icons/monitoring.png", - false, - }, - { - "RecordFront", - tr("Record and Upload Driver Camera"), - tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), - "../assets/icons/monitoring.png", - true, - }, - { - "RecordAudio", - tr("Record and Upload Microphone Audio"), - tr("Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect."), - "../assets/icons/microphone.png", - true, - }, - { - "IsMetric", - tr("Use Metric System"), - tr("Display speed in km/h instead of mph."), - "../assets/icons/metric.png", - false, - }, - }; - - - std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; - long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), - tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " - "In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with " - "your steering wheel distance button."), - "../assets/icons/speed_limit.png", - longi_button_texts); - - // set up uiState update for personality setting - QObject::connect(uiState(), &UIState::uiUpdate, this, &TogglesPanel::updateState); - - for (auto &[param, title, desc, icon, needs_restart] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); - - bool locked = params.getBool((param + "Lock").toStdString()); - toggle->setEnabled(!locked); - - if (needs_restart && !locked) { - toggle->setDescription(toggle->getDescription() + tr(" Changing this setting will restart openpilot if the car is powered on.")); - - QObject::connect(uiState(), &UIState::engagedChanged, [toggle](bool engaged) { - toggle->setEnabled(!engaged); - }); - - QObject::connect(toggle, &ParamControl::toggleFlipped, [=](bool state) { - params.putBool("OnroadCycleRequested", true); - }); - } - - addItem(toggle); - toggles[param.toStdString()] = toggle; - - // insert longitudinal personality after NDOG toggle - if (param == "DisengageOnAccelerator") { - addItem(long_personality_setting); - } - } - - // Toggles with confirmation dialogs - toggles["ExperimentalMode"]->setActiveIcon("../assets/icons/experimental.svg"); - toggles["ExperimentalMode"]->setConfirmation(true, true); -} - -void TogglesPanel::updateState(const UIState &s) { - const SubMaster &sm = *(s.sm); - - if (sm.updated("selfdriveState")) { - auto personality = sm["selfdriveState"].getSelfdriveState().getPersonality(); - if (personality != s.scene.personality && s.scene.started && isVisible()) { - long_personality_setting->setCheckedButton(static_cast(personality)); - } - uiState()->scene.personality = personality; - } -} - -void TogglesPanel::expandToggleDescription(const QString ¶m) { - toggles[param.toStdString()]->showDescription(); -} - -void TogglesPanel::scrollToToggle(const QString ¶m) { - if (auto it = toggles.find(param.toStdString()); it != toggles.end()) { - auto scroll_area = qobject_cast(parent()->parent()); - if (scroll_area) { - scroll_area->ensureWidgetVisible(it->second); - } - } -} - -void TogglesPanel::showEvent(QShowEvent *event) { - updateToggles(); -} - -void TogglesPanel::updateToggles() { - auto experimental_mode_toggle = toggles["ExperimentalMode"]; - const QString e2e_description = QString("%1
" - "

%2


" - "%3
" - "

%4


" - "%5
") - .arg(tr("openpilot defaults to driving in chill mode. Experimental mode enables alpha-level features that aren't ready for chill mode. Experimental features are listed below:")) - .arg(tr("End-to-End Longitudinal Control")) - .arg(tr("Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. " - "Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; " - "mistakes should be expected.")) - .arg(tr("New Driving Visualization")) - .arg(tr("The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.")); - - const bool is_release = params.getBool("IsReleaseBranch"); - auto cp_bytes = params.get("CarParamsPersistent"); - if (!cp_bytes.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - - if (hasLongitudinalControl(CP)) { - // normal description and toggle - experimental_mode_toggle->setEnabled(true); - experimental_mode_toggle->setDescription(e2e_description); - long_personality_setting->setEnabled(true); - } else { - // no long for now - experimental_mode_toggle->setEnabled(false); - long_personality_setting->setEnabled(false); - params.remove("ExperimentalMode"); - - const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control."); - - QString long_desc = unavailable + " " + \ - tr("openpilot longitudinal control may come in a future update."); - if (CP.getAlphaLongitudinalAvailable()) { - if (is_release) { - long_desc = unavailable + " " + tr("An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches."); - } else { - long_desc = tr("Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode."); - } - } - experimental_mode_toggle->setDescription("" + long_desc + "

" + e2e_description); - } - - experimental_mode_toggle->refresh(); - } else { - experimental_mode_toggle->setDescription(e2e_description); - } -} - -DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { - setSpacing(50); - addItem(new LabelControl(tr("Dongle ID"), getDongleId().value_or(tr("N/A")))); - addItem(new LabelControl(tr("Serial"), params.get("HardwareSerial").c_str())); - - pair_device = new ButtonControl(tr("Pair Device"), tr("PAIR"), - tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.")); - connect(pair_device, &ButtonControl::clicked, [=]() { - PairingPopup popup(this); - popup.exec(); - }); - addItem(pair_device); - - // offroad-only buttons - - auto dcamBtn = new ButtonControl(tr("Driver Camera"), tr("PREVIEW"), - tr("Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)")); - connect(dcamBtn, &ButtonControl::clicked, [=]() { emit showDriverView(); }); - addItem(dcamBtn); - - resetCalibBtn = new ButtonControl(tr("Reset Calibration"), tr("RESET"), ""); - connect(resetCalibBtn, &ButtonControl::showDescriptionEvent, this, &DevicePanel::updateCalibDescription); - connect(resetCalibBtn, &ButtonControl::clicked, [&]() { - if (!uiState()->engaged()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), tr("Reset"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.remove("CalibrationParams"); - params.remove("LiveTorqueParameters"); - params.remove("LiveParameters"); - params.remove("LiveParametersV2"); - params.remove("LiveDelay"); - params.putBool("OnroadCycleRequested", true); - updateCalibDescription(); - } - } - } else { - ConfirmationDialog::alert(tr("Disengage to Reset Calibration"), this); - } - }); - addItem(resetCalibBtn); - - auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of openpilot")); - connect(retrainingBtn, &ButtonControl::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) { - emit reviewTrainingGuide(); - } - }); - addItem(retrainingBtn); - - if (Hardware::TICI()) { - auto regulatoryBtn = new ButtonControl(tr("Regulatory"), tr("VIEW"), ""); - connect(regulatoryBtn, &ButtonControl::clicked, [=]() { - const std::string txt = util::read_file("../assets/offroad/fcc.html"); - ConfirmationDialog::rich(QString::fromStdString(txt), this); - }); - addItem(regulatoryBtn); - } - - auto translateBtn = new ButtonControl(tr("Change Language"), tr("CHANGE"), ""); - connect(translateBtn, &ButtonControl::clicked, [=]() { - QMap langs = getSupportedLanguages(); - QString selection = MultiOptionDialog::getSelection(tr("Select a language"), langs.keys(), langs.key(uiState()->language), this); - if (!selection.isEmpty()) { - // put language setting, exit Qt UI, and trigger fast restart - params.put("LanguageSetting", langs[selection].toStdString()); - qApp->exit(18); - } - }); - addItem(translateBtn); - - QObject::connect(uiState()->prime_state, &PrimeState::changed, [this] (PrimeState::Type type) { - pair_device->setVisible(type == PrimeState::PRIME_TYPE_UNPAIRED); - }); - QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - for (auto btn : findChildren()) { - if (btn != pair_device && btn != resetCalibBtn) { - btn->setEnabled(offroad); - } - } - }); - - // power buttons - QHBoxLayout *power_layout = new QHBoxLayout(); - power_layout->setSpacing(30); - - QPushButton *reboot_btn = new QPushButton(tr("Reboot")); - reboot_btn->setObjectName("reboot_btn"); - power_layout->addWidget(reboot_btn); - QObject::connect(reboot_btn, &QPushButton::clicked, this, &DevicePanel::reboot); - - QPushButton *poweroff_btn = new QPushButton(tr("Power Off")); - poweroff_btn->setObjectName("poweroff_btn"); - power_layout->addWidget(poweroff_btn); - QObject::connect(poweroff_btn, &QPushButton::clicked, this, &DevicePanel::poweroff); - - if (!Hardware::PC()) { - connect(uiState(), &UIState::offroadTransition, poweroff_btn, &QPushButton::setVisible); - } - - setStyleSheet(R"( - #reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; } - #reboot_btn:pressed { background-color: #4a4a4a; } - #poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; } - #poweroff_btn:pressed { background-color: #FF2424; } - )"); - addItem(power_layout); -} - -void DevicePanel::updateCalibDescription() { - QString desc = tr("openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down."); - std::string calib_bytes = params.get("CalibrationParams"); - if (!calib_bytes.empty()) { - try { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(calib_bytes.data(), calib_bytes.size())); - auto calib = cmsg.getRoot().getLiveCalibration(); - if (calib.getCalStatus() != cereal::LiveCalibrationData::Status::UNCALIBRATED) { - double pitch = calib.getRpyCalib()[1] * (180 / M_PI); - double yaw = calib.getRpyCalib()[2] * (180 / M_PI); - desc += tr(" Your device is pointed %1° %2 and %3° %4.") - .arg(QString::number(std::abs(pitch), 'g', 1), pitch > 0 ? tr("down") : tr("up"), - QString::number(std::abs(yaw), 'g', 1), yaw > 0 ? tr("left") : tr("right")); - } - } catch (kj::Exception) { - qInfo() << "invalid CalibrationParams"; - } - } - - int lag_perc = 0; - std::string lag_bytes = params.get("LiveDelay"); - if (!lag_bytes.empty()) { - try { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(lag_bytes.data(), lag_bytes.size())); - lag_perc = cmsg.getRoot().getLiveDelay().getCalPerc(); - } catch (kj::Exception) { - qInfo() << "invalid LiveDelay"; - } - } - if (lag_perc < 100) { - desc += tr("\n\nSteering lag calibration is %1% complete.").arg(lag_perc); - } else { - desc += tr("\n\nSteering lag calibration is complete."); - } - - std::string torque_bytes = params.get("LiveTorqueParameters"); - if (!torque_bytes.empty()) { - try { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(torque_bytes.data(), torque_bytes.size())); - auto torque = cmsg.getRoot().getLiveTorqueParameters(); - // don't add for non-torque cars - if (torque.getUseParams()) { - int torque_perc = torque.getCalPerc(); - if (torque_perc < 100) { - desc += tr(" Steering torque response calibration is %1% complete.").arg(torque_perc); - } else { - desc += tr(" Steering torque response calibration is complete."); - } - } - } catch (kj::Exception) { - qInfo() << "invalid LiveTorqueParameters"; - } - } - - desc += "\n\n"; - desc += tr("openpilot is continuously calibrating, resetting is rarely required. " - "Resetting calibration will restart openpilot if the car is powered on."); - resetCalibBtn->setDescription(desc); -} - -void DevicePanel::reboot() { - if (!uiState()->engaged()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reboot?"), tr("Reboot"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.putBool("DoReboot", true); - } - } - } else { - ConfirmationDialog::alert(tr("Disengage to Reboot"), this); - } -} - -void DevicePanel::poweroff() { - if (!uiState()->engaged()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), tr("Power Off"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.putBool("DoShutdown", true); - } - } - } else { - ConfirmationDialog::alert(tr("Disengage to Power Off"), this); - } -} - -void SettingsWindow::showEvent(QShowEvent *event) { - setCurrentPanel(0); -} - -void SettingsWindow::setCurrentPanel(int index, const QString ¶m) { - if (!param.isEmpty()) { - // Check if param ends with "Panel" to determine if it's a panel name - if (param.endsWith("Panel")) { - QString panelName = param; - panelName.chop(5); // Remove "Panel" suffix - - // Find the panel by name - for (int i = 0; i < nav_btns->buttons().size(); i++) { - if (nav_btns->buttons()[i]->text() == tr(panelName.toStdString().c_str())) { - index = i; - break; - } - } - } else { - emit expandToggleDescription(param); - emit scrollToToggle(param); - } - } - - panel_widget->setCurrentIndex(index); - nav_btns->buttons()[index]->setChecked(true); -} - -SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { - - // setup two main layouts - sidebar_widget = new QWidget; - QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget); - panel_widget = new QStackedWidget(); - - // close button - QPushButton *close_btn = new QPushButton(tr("×")); - close_btn->setStyleSheet(R"( - QPushButton { - font-size: 140px; - padding-bottom: 20px; - border-radius: 100px; - background-color: #292929; - font-weight: 400; - } - QPushButton:pressed { - background-color: #3B3B3B; - } - )"); - close_btn->setFixedSize(200, 200); - sidebar_layout->addSpacing(45); - sidebar_layout->addWidget(close_btn, 0, Qt::AlignCenter); - QObject::connect(close_btn, &QPushButton::clicked, this, &SettingsWindow::closeSettings); - - // setup panels - DevicePanel *device = new DevicePanel(this); - QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); - QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView); - - TogglesPanel *toggles = new TogglesPanel(this); - QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription); - QObject::connect(this, &SettingsWindow::scrollToToggle, toggles, &TogglesPanel::scrollToToggle); - - auto networking = new Networking(this); - QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &Networking::setPrimeType); - - QList> panels = { - {tr("Device"), device}, - {tr("Network"), networking}, - {tr("Toggles"), toggles}, - {tr("Software"), new SoftwarePanel(this)}, - {tr("Firehose"), new FirehosePanel(this)}, - {tr("Developer"), new DeveloperPanel(this)}, - }; - - nav_btns = new QButtonGroup(this); - for (auto &[name, panel] : panels) { - QPushButton *btn = new QPushButton(name); - btn->setCheckable(true); - btn->setChecked(nav_btns->buttons().size() == 0); - btn->setStyleSheet(R"( - QPushButton { - color: grey; - border: none; - background: none; - font-size: 65px; - font-weight: 500; - } - QPushButton:checked { - color: white; - } - QPushButton:pressed { - color: #ADADAD; - } - )"); - btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - nav_btns->addButton(btn); - sidebar_layout->addWidget(btn, 0, Qt::AlignRight); - - const int lr_margin = name != tr("Network") ? 50 : 0; // Network panel handles its own margins - panel->setContentsMargins(lr_margin, 25, lr_margin, 25); - - ScrollView *panel_frame = new ScrollView(panel, this); - panel_widget->addWidget(panel_frame); - - QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() { - btn->setChecked(true); - panel_widget->setCurrentWidget(w); - }); - } - sidebar_layout->setContentsMargins(50, 50, 100, 50); - - // main settings layout, sidebar + main panel - QHBoxLayout *main_layout = new QHBoxLayout(this); - - sidebar_widget->setFixedWidth(500); - main_layout->addWidget(sidebar_widget); - main_layout->addWidget(panel_widget); - - setStyleSheet(R"( - * { - color: white; - font-size: 50px; - } - SettingsWindow { - background-color: black; - } - QStackedWidget, ScrollView { - background-color: #292929; - border-radius: 30px; - } - )"); -} diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h deleted file mode 100644 index d52cf16bb7..0000000000 --- a/selfdrive/ui/qt/offroad/settings.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/controls.h" - -// ********** settings window + top-level panels ********** -class SettingsWindow : public QFrame { - Q_OBJECT - -public: - explicit SettingsWindow(QWidget *parent = 0); - void setCurrentPanel(int index, const QString ¶m = ""); - -protected: - void showEvent(QShowEvent *event) override; - -signals: - void closeSettings(); - void reviewTrainingGuide(); - void showDriverView(); - void expandToggleDescription(const QString ¶m); - void scrollToToggle(const QString ¶m); - -private: - QPushButton *sidebar_alert_widget; - QWidget *sidebar_widget; - QButtonGroup *nav_btns; - QStackedWidget *panel_widget; -}; - -class DevicePanel : public ListWidget { - Q_OBJECT -public: - explicit DevicePanel(SettingsWindow *parent); - -signals: - void reviewTrainingGuide(); - void showDriverView(); - -private slots: - void poweroff(); - void reboot(); - void updateCalibDescription(); - -private: - Params params; - ButtonControl *pair_device; - ButtonControl *resetCalibBtn; -}; - -class TogglesPanel : public ListWidget { - Q_OBJECT -public: - explicit TogglesPanel(SettingsWindow *parent); - void showEvent(QShowEvent *event) override; - -public slots: - void expandToggleDescription(const QString ¶m); - void scrollToToggle(const QString ¶m); - -private slots: - void updateState(const UIState &s); - -private: - Params params; - std::map toggles; - ButtonParamControl *long_personality_setting; - - void updateToggles(); -}; - -class SoftwarePanel : public ListWidget { - Q_OBJECT -public: - explicit SoftwarePanel(QWidget* parent = nullptr); - -private: - void showEvent(QShowEvent *event) override; - void updateLabels(); - void checkForUpdates(); - - bool is_onroad = false; - - QLabel *onroadLbl; - LabelControl *versionLbl; - ButtonControl *installBtn; - ButtonControl *downloadBtn; - ButtonControl *targetBranchBtn; - - Params params; - ParamWatcher *fs_watch; -}; - -// Forward declaration -class FirehosePanel; diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc deleted file mode 100644 index 9bc3fad3c9..0000000000 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ /dev/null @@ -1,156 +0,0 @@ -#include "selfdrive/ui/qt/offroad/settings.h" - -#include -#include -#include - -#include -#include - -#include "common/params.h" -#include "common/util.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "system/hardware/hw.h" - - -void SoftwarePanel::checkForUpdates() { - std::system("pkill -SIGUSR1 -f system.updated.updated"); -} - -SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { - onroadLbl = new QLabel(tr("Updates are only downloaded while the car is off.")); - onroadLbl->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; padding-top: 30px; padding-bottom: 30px;"); - addItem(onroadLbl); - - // current version - versionLbl = new LabelControl(tr("Current Version"), ""); - addItem(versionLbl); - - // download update btn - downloadBtn = new ButtonControl(tr("Download"), tr("CHECK")); - connect(downloadBtn, &ButtonControl::clicked, [=]() { - downloadBtn->setEnabled(false); - if (downloadBtn->text() == tr("CHECK")) { - checkForUpdates(); - } else { - std::system("pkill -SIGHUP -f system.updated.updated"); - } - }); - addItem(downloadBtn); - - // install update btn - installBtn = new ButtonControl(tr("Install Update"), tr("INSTALL")); - connect(installBtn, &ButtonControl::clicked, [=]() { - installBtn->setEnabled(false); - params.putBool("DoReboot", true); - }); - addItem(installBtn); - - // branch selecting - targetBranchBtn = new ButtonControl(tr("Target Branch"), tr("SELECT")); - connect(targetBranchBtn, &ButtonControl::clicked, [=]() { - auto current = params.get("GitBranch"); - QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(","); - for (QString b : {current.c_str(), "devel-staging", "devel", "nightly", "nightly-dev", "master"}) { - auto i = branches.indexOf(b); - if (i >= 0) { - branches.removeAt(i); - branches.insert(0, b); - } - } - - QString cur = QString::fromStdString(params.get("UpdaterTargetBranch")); - QString selection = MultiOptionDialog::getSelection(tr("Select a branch"), branches, cur, this); - if (!selection.isEmpty()) { - params.put("UpdaterTargetBranch", selection.toStdString()); - targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); - checkForUpdates(); - } - }); - if (!params.getBool("IsTestedBranch")) { - addItem(targetBranchBtn); - } - - // uninstall button - auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL")); - connect(uninstallBtn, &ButtonControl::clicked, [&]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to uninstall?"), tr("Uninstall"), this)) { - params.putBool("DoUninstall", true); - } - }); - addItem(uninstallBtn); - - fs_watch = new ParamWatcher(this); - QObject::connect(fs_watch, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - updateLabels(); - }); - - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - is_onroad = !offroad; - updateLabels(); - }); - - updateLabels(); -} - -void SoftwarePanel::showEvent(QShowEvent *event) { - // nice for testing on PC - installBtn->setEnabled(true); - - updateLabels(); -} - -void SoftwarePanel::updateLabels() { - // add these back in case the files got removed - fs_watch->addParam("LastUpdateTime"); - fs_watch->addParam("UpdateFailedCount"); - fs_watch->addParam("UpdaterState"); - fs_watch->addParam("UpdateAvailable"); - - if (!isVisible()) { - return; - } - - // updater only runs offroad - onroadLbl->setVisible(is_onroad); - downloadBtn->setVisible(!is_onroad); - - // download update - QString updater_state = QString::fromStdString(params.get("UpdaterState")); - bool failed = std::atoi(params.get("UpdateFailedCount").c_str()) > 0; - if (updater_state != "idle") { - downloadBtn->setEnabled(false); - downloadBtn->setValue(updater_state); - } else { - if (failed) { - downloadBtn->setText(tr("CHECK")); - downloadBtn->setValue(tr("failed to check for update")); - } else if (params.getBool("UpdaterFetchAvailable")) { - downloadBtn->setText(tr("DOWNLOAD")); - downloadBtn->setValue(tr("update available")); - } else { - QString lastUpdate = tr("never"); - auto tm = params.get("LastUpdateTime"); - if (!tm.empty()) { - lastUpdate = timeAgo(QDateTime::fromString(QString::fromStdString(tm + "Z"), Qt::ISODate)); - } - downloadBtn->setText(tr("CHECK")); - downloadBtn->setValue(tr("up to date, last checked %1").arg(lastUpdate)); - } - downloadBtn->setEnabled(true); - } - targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); - - // current + new versions - versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription"))); - versionLbl->setDescription(QString::fromStdString(params.get("UpdaterCurrentReleaseNotes"))); - - installBtn->setVisible(!is_onroad && params.getBool("UpdateAvailable")); - installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription"))); - installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes"))); - - update(); -} diff --git a/selfdrive/ui/qt/onroad/alerts.cc b/selfdrive/ui/qt/onroad/alerts.cc deleted file mode 100644 index 0236e20f16..0000000000 --- a/selfdrive/ui/qt/onroad/alerts.cc +++ /dev/null @@ -1,112 +0,0 @@ -#include "selfdrive/ui/qt/onroad/alerts.h" - -#include -#include - -#include "selfdrive/ui/qt/util.h" - -void OnroadAlerts::updateState(const UIState &s) { - Alert a = getAlert(*(s.sm), s.scene.started_frame); - if (!alert.equal(a)) { - alert = a; - update(); - } -} - -void OnroadAlerts::clear() { - alert = {}; - update(); -} - -OnroadAlerts::Alert OnroadAlerts::getAlert(const SubMaster &sm, uint64_t started_frame) { - const cereal::SelfdriveState::Reader &ss = sm["selfdriveState"].getSelfdriveState(); - const uint64_t selfdrive_frame = sm.rcv_frame("selfdriveState"); - - Alert a = {}; - if (selfdrive_frame >= started_frame) { // Don't get old alert. - a = {ss.getAlertText1().cStr(), ss.getAlertText2().cStr(), - ss.getAlertType().cStr(), ss.getAlertSize(), ss.getAlertStatus()}; - } - - if (!sm.updated("selfdriveState") && (sm.frame - started_frame) > 5 * UI_FREQ) { - const int SELFDRIVE_STATE_TIMEOUT = 5; - const int ss_missing = (nanos_since_boot() - sm.rcv_time("selfdriveState")) / 1e9; - - // Handle selfdrive timeout - if (selfdrive_frame < started_frame) { - // car is started, but selfdriveState hasn't been seen at all - a = {tr("openpilot Unavailable"), tr("Waiting to start"), - "selfdriveWaiting", cereal::SelfdriveState::AlertSize::MID, - cereal::SelfdriveState::AlertStatus::NORMAL}; - } else if (ss_missing > SELFDRIVE_STATE_TIMEOUT && !Hardware::PC()) { - // car is started, but selfdrive is lagging or died - if (ss.getEnabled() && (ss_missing - SELFDRIVE_STATE_TIMEOUT) < 10) { - a = {tr("TAKE CONTROL IMMEDIATELY"), tr("System Unresponsive"), - "selfdriveUnresponsive", cereal::SelfdriveState::AlertSize::FULL, - cereal::SelfdriveState::AlertStatus::CRITICAL}; - } else { - a = {tr("System Unresponsive"), tr("Reboot Device"), - "selfdriveUnresponsivePermanent", cereal::SelfdriveState::AlertSize::MID, - cereal::SelfdriveState::AlertStatus::NORMAL}; - } - } - } - return a; -} - -void OnroadAlerts::paintEvent(QPaintEvent *event) { - if (alert.size == cereal::SelfdriveState::AlertSize::NONE) { - return; - } - static std::map alert_heights = { - {cereal::SelfdriveState::AlertSize::SMALL, 271}, - {cereal::SelfdriveState::AlertSize::MID, 420}, - {cereal::SelfdriveState::AlertSize::FULL, height()}, - }; - int h = alert_heights[alert.size]; - - int margin = 40; - int radius = 30; - if (alert.size == cereal::SelfdriveState::AlertSize::FULL) { - margin = 0; - radius = 0; - } - QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2); - - QPainter p(this); - - // draw background + gradient - p.setPen(Qt::NoPen); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - p.setBrush(QBrush(alert_colors[alert.status])); - p.drawRoundedRect(r, radius, radius); - - QLinearGradient g(0, r.y(), 0, r.bottom()); - g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); - g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); - - p.setCompositionMode(QPainter::CompositionMode_DestinationOver); - p.setBrush(QBrush(g)); - p.drawRoundedRect(r, radius, radius); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - - // text - const QPoint c = r.center(); - p.setPen(QColor(0xff, 0xff, 0xff)); - p.setRenderHint(QPainter::TextAntialiasing); - if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) { - p.setFont(InterFont(74, QFont::DemiBold)); - p.drawText(r, Qt::AlignCenter, alert.text1); - } else if (alert.size == cereal::SelfdriveState::AlertSize::MID) { - p.setFont(InterFont(88, QFont::Bold)); - p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, alert.text1); - p.setFont(InterFont(66)); - p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, alert.text2); - } else if (alert.size == cereal::SelfdriveState::AlertSize::FULL) { - bool l = alert.text1.length() > 15; - p.setFont(InterFont(l ? 132 : 177, QFont::Bold)); - p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, alert.text1); - p.setFont(InterFont(88)); - p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, alert.text2); - } -} diff --git a/selfdrive/ui/qt/onroad/alerts.h b/selfdrive/ui/qt/onroad/alerts.h deleted file mode 100644 index de38d8ffc3..0000000000 --- a/selfdrive/ui/qt/onroad/alerts.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/ui/ui.h" - -class OnroadAlerts : public QWidget { - Q_OBJECT - -public: - OnroadAlerts(QWidget *parent = 0) : QWidget(parent) {} - void updateState(const UIState &s); - void clear(); - -protected: - struct Alert { - QString text1; - QString text2; - QString type; - cereal::SelfdriveState::AlertSize size; - cereal::SelfdriveState::AlertStatus status; - - bool equal(const Alert &other) const { - return text1 == other.text1 && text2 == other.text2 && type == other.type; - } - }; - - const QMap alert_colors = { - {cereal::SelfdriveState::AlertStatus::NORMAL, QColor(0x15, 0x15, 0x15, 0xf1)}, - {cereal::SelfdriveState::AlertStatus::USER_PROMPT, QColor(0xDA, 0x6F, 0x25, 0xf1)}, - {cereal::SelfdriveState::AlertStatus::CRITICAL, QColor(0xC9, 0x22, 0x31, 0xf1)}, - }; - - void paintEvent(QPaintEvent*) override; - OnroadAlerts::Alert getAlert(const SubMaster &sm, uint64_t started_frame); - - QColor bg; - Alert alert = {}; -}; diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc deleted file mode 100644 index f504ad69f1..0000000000 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ /dev/null @@ -1,157 +0,0 @@ - -#include "selfdrive/ui/qt/onroad/annotated_camera.h" - -#include -#include -#include - -#include "common/swaglog.h" -#include "selfdrive/ui/qt/util.h" - -// Window that shows camera view and variety of info drawn on top -AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget *parent) - : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, parent) { - pm = std::make_unique(std::vector{"uiDebug"}); - - main_layout = new QVBoxLayout(this); - main_layout->setMargin(UI_BORDER_SIZE); - main_layout->setSpacing(0); - - experimental_btn = new ExperimentalButton(this); - main_layout->addWidget(experimental_btn, 0, Qt::AlignTop | Qt::AlignRight); -} - -void AnnotatedCameraWidget::updateState(const UIState &s) { - // update engageability/experimental mode button - experimental_btn->updateState(s); - dmon.updateState(s); -} - -void AnnotatedCameraWidget::initializeGL() { - CameraWidget::initializeGL(); - qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION)); - qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR)); - qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER)); - qInfo() << "OpenGL language version:" << QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); - - prev_draw_t = millis_since_boot(); - setBackgroundColor(bg_colors[STATUS_DISENGAGED]); -} - -mat4 AnnotatedCameraWidget::calcFrameMatrix() { - // Project point at "infinity" to compute x and y offsets - // to ensure this ends up in the middle of the screen - // for narrow come and a little lower for wide cam. - // TODO: use proper perspective transform? - - // Select intrinsic matrix and calibration based on camera type - auto *s = uiState(); - bool wide_cam = active_stream_type == VISION_STREAM_WIDE_ROAD; - const auto &intrinsic_matrix = wide_cam ? ECAM_INTRINSIC_MATRIX : FCAM_INTRINSIC_MATRIX; - const auto &calibration = wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib; - - // Compute the calibration transformation matrix - const auto calib_transform = intrinsic_matrix * calibration; - - float zoom = wide_cam ? 2.0 : 1.1; - Eigen::Vector3f inf(1000., 0., 0.); - auto Kep = calib_transform * inf; - - int w = width(), h = height(); - float center_x = intrinsic_matrix(0, 2); - float center_y = intrinsic_matrix(1, 2); - - float max_x_offset = center_x * zoom - w / 2 - 5; - float max_y_offset = center_y * zoom - h / 2 - 5; - float x_offset = std::clamp((Kep.x() / Kep.z() - center_x) * zoom, -max_x_offset, max_x_offset); - float y_offset = std::clamp((Kep.y() / Kep.z() - center_y) * zoom, -max_y_offset, max_y_offset); - - // Apply transformation such that video pixel coordinates match video - // 1) Put (0, 0) in the middle of the video - // 2) Apply same scaling as video - // 3) Put (0, 0) in top left corner of video - Eigen::Matrix3f video_transform =(Eigen::Matrix3f() << - zoom, 0.0f, (w / 2 - x_offset) - (center_x * zoom), - 0.0f, zoom, (h / 2 - y_offset) - (center_y * zoom), - 0.0f, 0.0f, 1.0f).finished(); - - model.setTransform(video_transform * calib_transform); - - float zx = zoom * 2 * center_x / w; - float zy = zoom * 2 * center_y / h; - return mat4{{ - zx, 0.0, 0.0, -x_offset / w * 2, - 0.0, zy, 0.0, y_offset / h * 2, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; -} - -void AnnotatedCameraWidget::paintGL() { - UIState *s = uiState(); - SubMaster &sm = *(s->sm); - const double start_draw_t = millis_since_boot(); - - // draw camera frame - { - std::lock_guard lk(frame_lock); - - if (frames.empty()) { - if (skip_frame_count > 0) { - skip_frame_count--; - qDebug() << "skipping frame, not ready"; - return; - } - } else { - // skip drawing up to this many frames if we're - // missing camera frames. this smooths out the - // transitions from the narrow and wide cameras - skip_frame_count = 5; - } - - // Wide or narrow cam dependent on speed - bool has_wide_cam = available_streams.count(VISION_STREAM_WIDE_ROAD); - if (has_wide_cam) { - float v_ego = sm["carState"].getCarState().getVEgo(); - if ((v_ego < 10) || available_streams.size() == 1) { - wide_cam_requested = true; - } else if (v_ego > 15) { - wide_cam_requested = false; - } - wide_cam_requested = wide_cam_requested && sm["selfdriveState"].getSelfdriveState().getExperimentalMode(); - } - CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); - CameraWidget::setFrameId(sm["modelV2"].getModelV2().getFrameId()); - CameraWidget::paintGL(); - } - - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - painter.setPen(Qt::NoPen); - - model.draw(painter, rect()); - dmon.draw(painter, rect()); - hud.updateState(*s); - hud.draw(painter, rect()); - - double cur_draw_t = millis_since_boot(); - double dt = cur_draw_t - prev_draw_t; - double fps = fps_filter.update(1. / dt * 1000); - if (fps < 15) { - LOGW("slow frame rate: %.2f fps", fps); - } - prev_draw_t = cur_draw_t; - - // publish debug msg - MessageBuilder msg; - auto m = msg.initEvent().initUiDebug(); - m.setDrawTimeMillis(cur_draw_t - start_draw_t); - pm->send("uiDebug", msg); -} - -void AnnotatedCameraWidget::showEvent(QShowEvent *event) { - CameraWidget::showEvent(event); - - ui_update_params(uiState()); - prev_draw_t = millis_since_boot(); -} diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h deleted file mode 100644 index d205579f6c..0000000000 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include "selfdrive/ui/qt/onroad/hud.h" -#include "selfdrive/ui/qt/onroad/buttons.h" -#include "selfdrive/ui/qt/onroad/driver_monitoring.h" -#include "selfdrive/ui/qt/onroad/model.h" -#include "selfdrive/ui/qt/widgets/cameraview.h" - -class AnnotatedCameraWidget : public CameraWidget { - Q_OBJECT - -public: - explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0); - void updateState(const UIState &s); - -private: - QVBoxLayout *main_layout; - ExperimentalButton *experimental_btn; - DriverMonitorRenderer dmon; - HudRenderer hud; - ModelRenderer model; - std::unique_ptr pm; - - int skip_frame_count = 0; - bool wide_cam_requested = false; - -protected: - void paintGL() override; - void initializeGL() override; - void showEvent(QShowEvent *event) override; - mat4 calcFrameMatrix() override; - - double prev_draw_t = 0; - FirstOrderFilter fps_filter; -}; diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc deleted file mode 100644 index 32e58c9dba..0000000000 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include "selfdrive/ui/qt/onroad/buttons.h" - -#include - -#include "selfdrive/ui/qt/util.h" - -void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity) { - p.setRenderHint(QPainter::Antialiasing); - p.setOpacity(1.0); // bg dictates opacity of ellipse - p.setPen(Qt::NoPen); - p.setBrush(bg); - p.drawEllipse(center, btn_size / 2, btn_size / 2); - p.setOpacity(opacity); - p.drawPixmap(center - QPoint(img.width() / 2, img.height() / 2), img); - p.setOpacity(1.0); -} - -// ExperimentalButton -ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) { - setFixedSize(btn_size, btn_size); - - engage_img = loadPixmap("../assets/icons/chffr_wheel.png", {img_size, img_size}); - experimental_img = loadPixmap("../assets/icons/experimental.svg", {img_size, img_size}); - QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButton::changeMode); -} - -void ExperimentalButton::changeMode() { - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); - bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed"); - if (can_change) { - params.putBool("ExperimentalMode", !experimental_mode); - } -} - -void ExperimentalButton::updateState(const UIState &s) { - const auto cs = (*s.sm)["selfdriveState"].getSelfdriveState(); - bool eng = cs.getEngageable() || cs.getEnabled(); - if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { - engageable = eng; - experimental_mode = cs.getExperimentalMode(); - update(); - } -} - -void ExperimentalButton::paintEvent(QPaintEvent *event) { - QPainter p(this); - QPixmap img = experimental_mode ? experimental_img : engage_img; - drawIcon(p, QPoint(btn_size / 2, btn_size / 2), img, QColor(0, 0, 0, 166), (isDown() || !engageable) ? 0.6 : 1.0); -} diff --git a/selfdrive/ui/qt/onroad/buttons.h b/selfdrive/ui/qt/onroad/buttons.h deleted file mode 100644 index 9c91bc3c7b..0000000000 --- a/selfdrive/ui/qt/onroad/buttons.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/ui/ui.h" - -const int btn_size = 192; -const int img_size = (btn_size / 4) * 3; - -class ExperimentalButton : public QPushButton { - Q_OBJECT - -public: - explicit ExperimentalButton(QWidget *parent = 0); - void updateState(const UIState &s); - -private: - void paintEvent(QPaintEvent *event) override; - void changeMode(); - - Params params; - QPixmap engage_img; - QPixmap experimental_img; - bool experimental_mode; - bool engageable; -}; - -void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity); diff --git a/selfdrive/ui/qt/onroad/driver_monitoring.cc b/selfdrive/ui/qt/onroad/driver_monitoring.cc deleted file mode 100644 index 49f2c950b4..0000000000 --- a/selfdrive/ui/qt/onroad/driver_monitoring.cc +++ /dev/null @@ -1,107 +0,0 @@ -#include "selfdrive/ui/qt/onroad/driver_monitoring.h" -#include -#include - -#include "selfdrive/ui/qt/onroad/buttons.h" -#include "selfdrive/ui/qt/util.h" - -// Default 3D coordinates for face keypoints -static constexpr vec3 DEFAULT_FACE_KPTS_3D[] = { - {-5.98, -51.20, 8.00}, {-17.64, -49.14, 8.00}, {-23.81, -46.40, 8.00}, {-29.98, -40.91, 8.00}, {-32.04, -37.49, 8.00}, - {-34.10, -32.00, 8.00}, {-36.16, -21.03, 8.00}, {-36.16, 6.40, 8.00}, {-35.47, 10.51, 8.00}, {-32.73, 19.43, 8.00}, - {-29.30, 26.29, 8.00}, {-24.50, 33.83, 8.00}, {-19.01, 41.37, 8.00}, {-14.21, 46.17, 8.00}, {-12.16, 47.54, 8.00}, - {-4.61, 49.60, 8.00}, {4.99, 49.60, 8.00}, {12.53, 47.54, 8.00}, {14.59, 46.17, 8.00}, {19.39, 41.37, 8.00}, - {24.87, 33.83, 8.00}, {29.67, 26.29, 8.00}, {33.10, 19.43, 8.00}, {35.84, 10.51, 8.00}, {36.53, 6.40, 8.00}, - {36.53, -21.03, 8.00}, {34.47, -32.00, 8.00}, {32.42, -37.49, 8.00}, {30.36, -40.91, 8.00}, {24.19, -46.40, 8.00}, - {18.02, -49.14, 8.00}, {6.36, -51.20, 8.00}, {-5.98, -51.20, 8.00}, -}; - -// Colors used for drawing based on monitoring state -static const QColor DMON_ENGAGED_COLOR = QColor::fromRgbF(0.1, 0.945, 0.26); -static const QColor DMON_DISENGAGED_COLOR = QColor::fromRgbF(0.545, 0.545, 0.545); - -DriverMonitorRenderer::DriverMonitorRenderer() : face_kpts_draw(std::size(DEFAULT_FACE_KPTS_3D)) { - dm_img = loadPixmap("../assets/icons/driver_face.png", {img_size + 5, img_size + 5}); -} - -void DriverMonitorRenderer::updateState(const UIState &s) { - auto &sm = *(s.sm); - is_visible = sm["selfdriveState"].getSelfdriveState().getAlertSize() == cereal::SelfdriveState::AlertSize::NONE && - sm.rcv_frame("driverStateV2") > s.scene.started_frame; - if (!is_visible) return; - - auto dm_state = sm["driverMonitoringState"].getDriverMonitoringState(); - is_active = dm_state.getIsActiveMode(); - is_rhd = dm_state.getIsRHD(); - dm_fade_state = std::clamp(dm_fade_state + 0.2f * (0.5f - is_active), 0.0f, 1.0f); - - const auto &driverstate = sm["driverStateV2"].getDriverStateV2(); - const auto driver_orient = is_rhd ? driverstate.getRightDriverData().getFaceOrientation() : driverstate.getLeftDriverData().getFaceOrientation(); - - for (int i = 0; i < 3; ++i) { - float v_this = (i == 0 ? (driver_orient[i] < 0 ? 0.7 : 0.9) : 0.4) * driver_orient[i]; - driver_pose_diff[i] = std::abs(driver_pose_vals[i] - v_this); - driver_pose_vals[i] = 0.8f * v_this + (1 - 0.8) * driver_pose_vals[i]; - driver_pose_sins[i] = std::sin(driver_pose_vals[i] * (1.0f - dm_fade_state)); - driver_pose_coss[i] = std::cos(driver_pose_vals[i] * (1.0f - dm_fade_state)); - } - - auto [sin_y, sin_x, sin_z] = driver_pose_sins; - auto [cos_y, cos_x, cos_z] = driver_pose_coss; - - // Rotation matrix for transforming face keypoints based on driver's head orientation - const mat3 r_xyz = {{ - cos_x * cos_z, cos_x * sin_z, -sin_x, - -sin_y * sin_x * cos_z - cos_y * sin_z, -sin_y * sin_x * sin_z + cos_y * cos_z, -sin_y * cos_x, - cos_y * sin_x * cos_z - sin_y * sin_z, cos_y * sin_x * sin_z + sin_y * cos_z, cos_y * cos_x, - }}; - - // Transform vertices - for (int i = 0; i < face_kpts_draw.size(); ++i) { - vec3 kpt = matvecmul3(r_xyz, DEFAULT_FACE_KPTS_3D[i]); - face_kpts_draw[i] = {{kpt.v[0], kpt.v[1], kpt.v[2] * (1.0f - dm_fade_state) + 8 * dm_fade_state}}; - } -} - -void DriverMonitorRenderer::draw(QPainter &painter, const QRect &surface_rect) { - if (!is_visible) return; - - painter.save(); - - int offset = UI_BORDER_SIZE + btn_size / 2; - float x = is_rhd ? surface_rect.width() - offset : offset; - float y = surface_rect.height() - offset; - float opacity = is_active ? 0.65f : 0.2f; - - drawIcon(painter, QPoint(x, y), dm_img, QColor(0, 0, 0, 70), opacity); - - QPointF keypoints[std::size(DEFAULT_FACE_KPTS_3D)]; - for (int i = 0; i < std::size(keypoints); ++i) { - const auto &v = face_kpts_draw[i].v; - float kp = (v[2] - 8) / 120.0f + 1.0f; - keypoints[i] = QPointF(v[0] * kp + x, v[1] * kp + y); - } - - painter.setPen(QPen(QColor::fromRgbF(1.0, 1.0, 1.0, opacity), 5.2, Qt::SolidLine, Qt::RoundCap)); - painter.drawPolyline(keypoints, std::size(keypoints)); - - // tracking arcs - const int arc_l = 133; - const float arc_t_default = 6.7f; - const float arc_t_extend = 12.0f; - QColor arc_color = uiState()->engaged() ? DMON_ENGAGED_COLOR : DMON_DISENGAGED_COLOR; - arc_color.setAlphaF(0.4 * (1.0f - dm_fade_state)); - - float delta_x = -driver_pose_sins[1] * arc_l / 2.0f; - float delta_y = -driver_pose_sins[0] * arc_l / 2.0f; - - // Draw horizontal tracking arc - painter.setPen(QPen(arc_color, arc_t_default + arc_t_extend * std::min(1.0, driver_pose_diff[1] * 5.0), Qt::SolidLine, Qt::RoundCap)); - painter.drawArc(QRectF(std::min(x + delta_x, x), y - arc_l / 2, std::abs(delta_x), arc_l), (driver_pose_sins[1] > 0 ? 90 : -90) * 16, 180 * 16); - - // Draw vertical tracking arc - painter.setPen(QPen(arc_color, arc_t_default + arc_t_extend * std::min(1.0, driver_pose_diff[0] * 5.0), Qt::SolidLine, Qt::RoundCap)); - painter.drawArc(QRectF(x - arc_l / 2, std::min(y + delta_y, y), arc_l, std::abs(delta_y)), (driver_pose_sins[0] > 0 ? 0 : 180) * 16, 180 * 16); - - painter.restore(); -} diff --git a/selfdrive/ui/qt/onroad/driver_monitoring.h b/selfdrive/ui/qt/onroad/driver_monitoring.h deleted file mode 100644 index 47db151c81..0000000000 --- a/selfdrive/ui/qt/onroad/driver_monitoring.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include -#include "selfdrive/ui/ui.h" - -class DriverMonitorRenderer { -public: - DriverMonitorRenderer(); - void updateState(const UIState &s); - void draw(QPainter &painter, const QRect &surface_rect); - -private: - float driver_pose_vals[3] = {}; - float driver_pose_diff[3] = {}; - float driver_pose_sins[3] = {}; - float driver_pose_coss[3] = {}; - bool is_visible = false; - bool is_active = false; - bool is_rhd = false; - float dm_fade_state = 1.0; - QPixmap dm_img; - std::vector face_kpts_draw; -}; diff --git a/selfdrive/ui/qt/onroad/hud.cc b/selfdrive/ui/qt/onroad/hud.cc deleted file mode 100644 index 4cfa3d0e3c..0000000000 --- a/selfdrive/ui/qt/onroad/hud.cc +++ /dev/null @@ -1,112 +0,0 @@ -#include "selfdrive/ui/qt/onroad/hud.h" - -#include - -#include "selfdrive/ui/qt/util.h" - -constexpr int SET_SPEED_NA = 255; - -HudRenderer::HudRenderer() {} - -void HudRenderer::updateState(const UIState &s) { - is_metric = s.scene.is_metric; - status = s.status; - - const SubMaster &sm = *(s.sm); - if (sm.rcv_frame("carState") < s.scene.started_frame) { - is_cruise_set = false; - set_speed = SET_SPEED_NA; - speed = 0.0; - return; - } - - const auto &controls_state = sm["controlsState"].getControlsState(); - const auto &car_state = sm["carState"].getCarState(); - - // Handle older routes where vCruiseCluster is not set - set_speed = car_state.getVCruiseCluster() == 0.0 ? controls_state.getVCruiseDEPRECATED() : car_state.getVCruiseCluster(); - is_cruise_set = set_speed > 0 && set_speed != SET_SPEED_NA; - is_cruise_available = set_speed != -1; - - if (is_cruise_set && !is_metric) { - set_speed *= KM_TO_MILE; - } - - // Handle older routes where vEgoCluster is not set - v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; - float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo(); - speed = std::max(0.0f, v_ego * (is_metric ? MS_TO_KPH : MS_TO_MPH)); -} - -void HudRenderer::draw(QPainter &p, const QRect &surface_rect) { - p.save(); - - // Draw header gradient - QLinearGradient bg(0, UI_HEADER_HEIGHT - (UI_HEADER_HEIGHT / 2.5), 0, UI_HEADER_HEIGHT); - bg.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.45)); - bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); - p.fillRect(0, 0, surface_rect.width(), UI_HEADER_HEIGHT, bg); - - - if (is_cruise_available) { - drawSetSpeed(p, surface_rect); - } - drawCurrentSpeed(p, surface_rect); - - p.restore(); -} - -void HudRenderer::drawSetSpeed(QPainter &p, const QRect &surface_rect) { - // Draw outer box + border to contain set speed - const QSize default_size = {172, 204}; - QSize set_speed_size = is_metric ? QSize(200, 204) : default_size; - QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size); - - // Draw set speed box - p.setPen(QPen(QColor(255, 255, 255, 75), 6)); - p.setBrush(QColor(0, 0, 0, 166)); - p.drawRoundedRect(set_speed_rect, 32, 32); - - // Colors based on status - QColor max_color = QColor(0xa6, 0xa6, 0xa6, 0xff); - QColor set_speed_color = QColor(0x72, 0x72, 0x72, 0xff); - if (is_cruise_set) { - set_speed_color = QColor(255, 255, 255); - if (status == STATUS_DISENGAGED) { - max_color = QColor(255, 255, 255); - } else if (status == STATUS_OVERRIDE) { - max_color = QColor(0x91, 0x9b, 0x95, 0xff); - } else { - max_color = QColor(0x80, 0xd8, 0xa6, 0xff); - } - } - - // Draw "MAX" text - p.setFont(InterFont(40, QFont::DemiBold)); - p.setPen(max_color); - p.drawText(set_speed_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("MAX")); - - // Draw set speed - QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–"; - p.setFont(InterFont(90, QFont::Bold)); - p.setPen(set_speed_color); - p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); -} - -void HudRenderer::drawCurrentSpeed(QPainter &p, const QRect &surface_rect) { - QString speedStr = QString::number(std::nearbyint(speed)); - - p.setFont(InterFont(176, QFont::Bold)); - drawText(p, surface_rect.center().x(), 210, speedStr); - - p.setFont(InterFont(66)); - drawText(p, surface_rect.center().x(), 290, is_metric ? tr("km/h") : tr("mph"), 200); -} - -void HudRenderer::drawText(QPainter &p, int x, int y, const QString &text, int alpha) { - QRect real_rect = p.fontMetrics().boundingRect(text); - real_rect.moveCenter({x, y - real_rect.height() / 2}); - - p.setPen(QColor(0xff, 0xff, 0xff, alpha)); - p.drawText(real_rect.x(), real_rect.bottom(), text); -} diff --git a/selfdrive/ui/qt/onroad/hud.h b/selfdrive/ui/qt/onroad/hud.h deleted file mode 100644 index b2ac379dbe..0000000000 --- a/selfdrive/ui/qt/onroad/hud.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include "selfdrive/ui/ui.h" - -class HudRenderer : public QObject { - Q_OBJECT - -public: - HudRenderer(); - void updateState(const UIState &s); - void draw(QPainter &p, const QRect &surface_rect); - -private: - void drawSetSpeed(QPainter &p, const QRect &surface_rect); - void drawCurrentSpeed(QPainter &p, const QRect &surface_rect); - void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); - - float speed = 0; - float set_speed = 0; - bool is_cruise_set = false; - bool is_cruise_available = true; - bool is_metric = false; - bool v_ego_cluster_seen = false; - int status = STATUS_DISENGAGED; -}; diff --git a/selfdrive/ui/qt/onroad/model.cc b/selfdrive/ui/qt/onroad/model.cc deleted file mode 100644 index 52902abdc8..0000000000 --- a/selfdrive/ui/qt/onroad/model.cc +++ /dev/null @@ -1,250 +0,0 @@ -#include "selfdrive/ui/qt/onroad/model.h" - -constexpr int CLIP_MARGIN = 500; -constexpr float MIN_DRAW_DISTANCE = 10.0; -constexpr float MAX_DRAW_DISTANCE = 100.0; - -static int get_path_length_idx(const cereal::XYZTData::Reader &line, const float path_height) { - const auto &line_x = line.getX(); - int max_idx = 0; - for (int i = 1; i < line_x.size() && line_x[i] <= path_height; ++i) { - max_idx = i; - } - return max_idx; -} - -void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) { - auto *s = uiState(); - auto &sm = *(s->sm); - // Check if data is up-to-date - if (sm.rcv_frame("liveCalibration") < s->scene.started_frame || - sm.rcv_frame("modelV2") < s->scene.started_frame) { - return; - } - - clip_region = surface_rect.adjusted(-CLIP_MARGIN, -CLIP_MARGIN, CLIP_MARGIN, CLIP_MARGIN); - experimental_mode = sm["selfdriveState"].getSelfdriveState().getExperimentalMode(); - longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); - path_offset_z = sm["liveCalibration"].getLiveCalibration().getHeight()[0]; - - painter.save(); - - const auto &model = sm["modelV2"].getModelV2(); - const auto &radar_state = sm["radarState"].getRadarState(); - const auto &lead_one = radar_state.getLeadOne(); - - update_model(model, lead_one); - drawLaneLines(painter); - drawPath(painter, model, surface_rect.height()); - - if (longitudinal_control && sm.alive("radarState")) { - update_leads(radar_state, model.getPosition()); - const auto &lead_two = radar_state.getLeadTwo(); - if (lead_one.getStatus()) { - drawLead(painter, lead_one, lead_vertices[0], surface_rect); - } - if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { - drawLead(painter, lead_two, lead_vertices[1], surface_rect); - } - } - - painter.restore(); -} - -void ModelRenderer::update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line) { - for (int i = 0; i < 2; ++i) { - const auto &lead_data = (i == 0) ? radar_state.getLeadOne() : radar_state.getLeadTwo(); - if (lead_data.getStatus()) { - float z = line.getZ()[get_path_length_idx(line, lead_data.getDRel())]; - mapToScreen(lead_data.getDRel(), -lead_data.getYRel(), z + path_offset_z, &lead_vertices[i]); - } - } -} - -void ModelRenderer::update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) { - const auto &model_position = model.getPosition(); - float max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); - - // update lane lines - const auto &lane_lines = model.getLaneLines(); - const auto &line_probs = model.getLaneLineProbs(); - int max_idx = get_path_length_idx(lane_lines[0], max_distance); - for (int i = 0; i < std::size(lane_line_vertices); i++) { - lane_line_probs[i] = line_probs[i]; - mapLineToPolygon(lane_lines[i], 0.025 * lane_line_probs[i], 0, &lane_line_vertices[i], max_idx); - } - - // update road edges - const auto &road_edges = model.getRoadEdges(); - const auto &edge_stds = model.getRoadEdgeStds(); - for (int i = 0; i < std::size(road_edge_vertices); i++) { - road_edge_stds[i] = edge_stds[i]; - mapLineToPolygon(road_edges[i], 0.025, 0, &road_edge_vertices[i], max_idx); - } - - // update path - if (lead.getStatus()) { - const float lead_d = lead.getDRel() * 2.; - max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); - } - max_idx = get_path_length_idx(model_position, max_distance); - mapLineToPolygon(model_position, 0.9, path_offset_z, &track_vertices, max_idx, false); -} - -void ModelRenderer::drawLaneLines(QPainter &painter) { - // lanelines - for (int i = 0; i < std::size(lane_line_vertices); ++i) { - painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(lane_line_probs[i], 0.0, 0.7))); - painter.drawPolygon(lane_line_vertices[i]); - } - - // road edges - for (int i = 0; i < std::size(road_edge_vertices); ++i) { - painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - road_edge_stds[i], 0.0, 1.0))); - painter.drawPolygon(road_edge_vertices[i]); - } -} - -void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height) { - QLinearGradient bg(0, height, 0, 0); - if (experimental_mode) { - // The first half of track_vertices are the points for the right side of the path - const auto &acceleration = model.getAcceleration().getX(); - const int max_len = std::min(track_vertices.length() / 2, acceleration.size()); - - for (int i = 0; i < max_len; ++i) { - // Some points are out of frame - int track_idx = max_len - i - 1; // flip idx to start from bottom right - if (track_vertices[track_idx].y() < 0 || track_vertices[track_idx].y() > height) continue; - - // Flip so 0 is bottom of frame - float lin_grad_point = (height - track_vertices[track_idx].y()) / height; - - // speed up: 120, slow down: 0 - float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); - // FIXME: painter.drawPolygon can be slow if hue is not rounded - path_hue = int(path_hue * 100 + 0.5) / 100; - - float saturation = fmin(fabs(acceleration[i] * 1.5), 1); - float lightness = util::map_val(saturation, 0.0f, 1.0f, 0.95f, 0.62f); // lighter when grey - float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.4f, 0.0f); // matches previous alpha fade - bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360., saturation, lightness, alpha)); - - // Skip a point, unless next is last - i += (i + 2) < max_len ? 1 : 0; - } - - } else { - updatePathGradient(bg); - } - - painter.setBrush(bg); - painter.drawPolygon(track_vertices); -} - -void ModelRenderer::updatePathGradient(QLinearGradient &bg) { - static const QColor throttle_colors[] = { - QColor::fromHslF(148. / 360., 0.94, 0.51, 0.4), - QColor::fromHslF(112. / 360., 1.0, 0.68, 0.35), - QColor::fromHslF(112. / 360., 1.0, 0.68, 0.0)}; - - static const QColor no_throttle_colors[] = { - QColor::fromHslF(148. / 360., 0.0, 0.95, 0.4), - QColor::fromHslF(112. / 360., 0.0, 0.95, 0.35), - QColor::fromHslF(112. / 360., 0.0, 0.95, 0.0), - }; - - // Transition speed; 0.1 corresponds to 0.5 seconds at UI_FREQ - constexpr float transition_speed = 0.1f; - - // Start transition if throttle state changes - bool allow_throttle = (*uiState()->sm)["longitudinalPlan"].getLongitudinalPlan().getAllowThrottle() || !longitudinal_control; - if (allow_throttle != prev_allow_throttle) { - prev_allow_throttle = allow_throttle; - // Invert blend factor for a smooth transition when the state changes mid-animation - blend_factor = std::max(1.0f - blend_factor, 0.0f); - } - - const QColor *begin_colors = allow_throttle ? no_throttle_colors : throttle_colors; - const QColor *end_colors = allow_throttle ? throttle_colors : no_throttle_colors; - if (blend_factor < 1.0f) { - blend_factor = std::min(blend_factor + transition_speed, 1.0f); - } - - // Set gradient colors by blending the start and end colors - bg.setColorAt(0.0f, blendColors(begin_colors[0], end_colors[0], blend_factor)); - bg.setColorAt(0.5f, blendColors(begin_colors[1], end_colors[1], blend_factor)); - bg.setColorAt(1.0f, blendColors(begin_colors[2], end_colors[2], blend_factor)); -} - -QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float t) { - if (t == 1.0f) return end; - return QColor::fromRgbF( - (1 - t) * start.redF() + t * end.redF(), - (1 - t) * start.greenF() + t * end.greenF(), - (1 - t) * start.blueF() + t * end.blueF(), - (1 - t) * start.alphaF() + t * end.alphaF()); -} - -void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, - const QPointF &vd, const QRect &surface_rect) { - const float speedBuff = 10.; - const float leadBuff = 40.; - const float d_rel = lead_data.getDRel(); - const float v_rel = lead_data.getVRel(); - - float fillAlpha = 0; - if (d_rel < leadBuff) { - fillAlpha = 255 * (1.0 - (d_rel / leadBuff)); - if (v_rel < 0) { - fillAlpha += 255 * (-1 * (v_rel / speedBuff)); - } - fillAlpha = (int)(fmin(fillAlpha, 255)); - } - - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; - float x = std::clamp(vd.x(), 0.f, surface_rect.width() - sz / 2); - float y = std::min(vd.y(), surface_rect.height() - sz * 0.6); - - float g_xo = sz / 5; - float g_yo = sz / 10; - - QPointF glow[] = {{x + (sz * 1.35) + g_xo, y + sz + g_yo}, {x, y - g_yo}, {x - (sz * 1.35) - g_xo, y + sz + g_yo}}; - painter.setBrush(QColor(218, 202, 37, 255)); - painter.drawPolygon(glow, std::size(glow)); - - // chevron - QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}}; - painter.setBrush(QColor(201, 34, 49, fillAlpha)); - painter.drawPolygon(chevron, std::size(chevron)); -} - -// Projects a point in car to space to the corresponding point in full frame image space. -bool ModelRenderer::mapToScreen(float in_x, float in_y, float in_z, QPointF *out) { - Eigen::Vector3f input(in_x, in_y, in_z); - auto pt = car_space_transform * input; - *out = QPointF(pt.x() / pt.z(), pt.y() / pt.z()); - return clip_region.contains(*out); -} - -void ModelRenderer::mapLineToPolygon(const cereal::XYZTData::Reader &line, float y_off, float z_off, - QPolygonF *pvd, int max_idx, bool allow_invert) { - const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); - QPointF left, right; - pvd->clear(); - for (int i = 0; i <= max_idx; i++) { - // highly negative x positions are drawn above the frame and cause flickering, clip to zy plane of camera - if (line_x[i] < 0) continue; - - bool l = mapToScreen(line_x[i], line_y[i] - y_off, line_z[i] + z_off, &left); - bool r = mapToScreen(line_x[i], line_y[i] + y_off, line_z[i] + z_off, &right); - if (l && r) { - // For wider lines the drawn polygon will "invert" when going over a hill and cause artifacts - if (!allow_invert && pvd->size() && left.y() > pvd->back().y()) { - continue; - } - pvd->push_back(left); - pvd->push_front(right); - } - } -} diff --git a/selfdrive/ui/qt/onroad/model.h b/selfdrive/ui/qt/onroad/model.h deleted file mode 100644 index 79547e4b83..0000000000 --- a/selfdrive/ui/qt/onroad/model.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include - -#include "selfdrive/ui/ui.h" - -class ModelRenderer { -public: - ModelRenderer() {} - void setTransform(const Eigen::Matrix3f &transform) { car_space_transform = transform; } - void draw(QPainter &painter, const QRect &surface_rect); - -private: - bool mapToScreen(float in_x, float in_y, float in_z, QPointF *out); - void mapLineToPolygon(const cereal::XYZTData::Reader &line, float y_off, float z_off, - QPolygonF *pvd, int max_idx, bool allow_invert = true); - void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, const QRect &surface_rect); - void update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line); - void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead); - void drawLaneLines(QPainter &painter); - void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height); - void updatePathGradient(QLinearGradient &bg); - QColor blendColors(const QColor &start, const QColor &end, float t); - - bool longitudinal_control = false; - bool experimental_mode = false; - float blend_factor = 1.0f; - bool prev_allow_throttle = true; - float lane_line_probs[4] = {}; - float road_edge_stds[2] = {}; - float path_offset_z = 1.22f; - QPolygonF track_vertices; - QPolygonF lane_line_vertices[4] = {}; - QPolygonF road_edge_vertices[2] = {}; - QPointF lead_vertices[2] = {}; - Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero(); - QRectF clip_region; -}; diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc deleted file mode 100644 index 080f9bd50f..0000000000 --- a/selfdrive/ui/qt/onroad/onroad_home.cc +++ /dev/null @@ -1,65 +0,0 @@ -#include "selfdrive/ui/qt/onroad/onroad_home.h" - -#include -#include - -#include "selfdrive/ui/qt/util.h" - -OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(UI_BORDER_SIZE); - QStackedLayout *stacked_layout = new QStackedLayout; - stacked_layout->setStackingMode(QStackedLayout::StackAll); - main_layout->addLayout(stacked_layout); - - nvg = new AnnotatedCameraWidget(VISION_STREAM_ROAD, this); - - QWidget * split_wrapper = new QWidget; - split = new QHBoxLayout(split_wrapper); - split->setContentsMargins(0, 0, 0, 0); - split->setSpacing(0); - split->addWidget(nvg); - - if (getenv("DUAL_CAMERA_VIEW")) { - CameraWidget *arCam = new CameraWidget("camerad", VISION_STREAM_ROAD, this); - split->insertWidget(0, arCam); - } - - stacked_layout->addWidget(split_wrapper); - - alerts = new OnroadAlerts(this); - alerts->setAttribute(Qt::WA_TransparentForMouseEvents, true); - stacked_layout->addWidget(alerts); - - // setup stacking order - alerts->raise(); - - setAttribute(Qt::WA_OpaquePaintEvent); - QObject::connect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState); - QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition); -} - -void OnroadWindow::updateState(const UIState &s) { - if (!s.scene.started) { - return; - } - - alerts->updateState(s); - nvg->updateState(s); - - QColor bgColor = bg_colors[s.status]; - if (bg != bgColor) { - // repaint border - bg = bgColor; - update(); - } -} - -void OnroadWindow::offroadTransition(bool offroad) { - alerts->clear(); -} - -void OnroadWindow::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255)); -} diff --git a/selfdrive/ui/qt/onroad/onroad_home.h b/selfdrive/ui/qt/onroad/onroad_home.h deleted file mode 100644 index c321d2d44f..0000000000 --- a/selfdrive/ui/qt/onroad/onroad_home.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/onroad/alerts.h" -#include "selfdrive/ui/qt/onroad/annotated_camera.h" - -class OnroadWindow : public QWidget { - Q_OBJECT - -public: - OnroadWindow(QWidget* parent = 0); - -private: - void paintEvent(QPaintEvent *event); - OnroadAlerts *alerts; - AnnotatedCameraWidget *nvg; - QColor bg = bg_colors[STATUS_DISENGAGED]; - QHBoxLayout* split; - -private slots: - void offroadTransition(bool offroad); - void updateState(const UIState &s); -}; diff --git a/selfdrive/ui/qt/prime_state.cc b/selfdrive/ui/qt/prime_state.cc deleted file mode 100644 index f12daf1e3c..0000000000 --- a/selfdrive/ui/qt/prime_state.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "selfdrive/ui/qt/prime_state.h" - -#include - -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/qt/request_repeater.h" -#include "selfdrive/ui/qt/util.h" - -PrimeState::PrimeState(QObject* parent) : QObject(parent) { - const char *env_prime_type = std::getenv("PRIME_TYPE"); - auto type = env_prime_type ? env_prime_type : Params().get("PrimeType"); - - if (!type.empty()) { - prime_type = static_cast(std::atoi(type.c_str())); - } - - if (auto dongleId = getDongleId()) { - QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/"; - RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 5); - QObject::connect(repeater, &RequestRepeater::requestDone, this, &PrimeState::handleReply); - } - - // Emit the initial state change - QTimer::singleShot(1, [this]() { emit changed(prime_type); }); -} - -void PrimeState::handleReply(const QString& response, bool success) { - if (!success) return; - - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting pairing and PrimeState status"; - return; - } - - QJsonObject json = doc.object(); - bool is_paired = json["is_paired"].toBool(); - auto type = static_cast(json["prime_type"].toInt()); - setType(is_paired ? type : PrimeState::PRIME_TYPE_UNPAIRED); -} - -void PrimeState::setType(PrimeState::Type type) { - if (type != prime_type) { - prime_type = type; - Params().put("PrimeType", std::to_string(prime_type)); - emit changed(prime_type); - } -} diff --git a/selfdrive/ui/qt/prime_state.h b/selfdrive/ui/qt/prime_state.h deleted file mode 100644 index 0e2e3bb043..0000000000 --- a/selfdrive/ui/qt/prime_state.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -class PrimeState : public QObject { - Q_OBJECT - -public: - - enum Type { - PRIME_TYPE_UNKNOWN = -2, - PRIME_TYPE_UNPAIRED = -1, - PRIME_TYPE_NONE = 0, - PRIME_TYPE_MAGENTA = 1, - PRIME_TYPE_LITE = 2, - PRIME_TYPE_BLUE = 3, - PRIME_TYPE_MAGENTA_NEW = 4, - PRIME_TYPE_PURPLE = 5, - }; - - PrimeState(QObject *parent); - void setType(PrimeState::Type type); - inline PrimeState::Type currentType() const { return prime_type; } - inline bool isSubscribed() const { return prime_type > PrimeState::PRIME_TYPE_NONE; } - -signals: - void changed(PrimeState::Type prime_type); - -private: - void handleReply(const QString &response, bool success); - - PrimeState::Type prime_type = PrimeState::PRIME_TYPE_UNKNOWN; -}; diff --git a/selfdrive/ui/qt/qt_window.cc b/selfdrive/ui/qt/qt_window.cc deleted file mode 100644 index cdd817ae2f..0000000000 --- a/selfdrive/ui/qt/qt_window.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include "selfdrive/ui/qt/qt_window.h" - -void setMainWindow(QWidget *w) { - const float scale = util::getenv("SCALE", 1.0f); - const QSize sz = QGuiApplication::primaryScreen()->size(); - - if (Hardware::PC() && scale == 1.0 && !(sz - DEVICE_SCREEN_SIZE).isValid()) { - w->setMinimumSize(QSize(640, 480)); // allow resize smaller than fullscreen - w->setMaximumSize(DEVICE_SCREEN_SIZE); - w->resize(sz); - } else { - w->setFixedSize(DEVICE_SCREEN_SIZE * scale); - } - w->show(); - -#ifdef __TICI__ - QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface(); - wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", w->windowHandle())); - wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270); - wl_surface_commit(s); - - w->setWindowState(Qt::WindowFullScreen); - w->setVisible(true); - - // ensure we have a valid eglDisplay, otherwise the ui will silently fail - void *egl = native->nativeResourceForWindow("egldisplay", w->windowHandle()); - assert(egl != nullptr); -#endif -} - - -extern "C" { - void set_main_window(void *w) { - setMainWindow((QWidget*)w); - } -} diff --git a/selfdrive/ui/qt/qt_window.h b/selfdrive/ui/qt/qt_window.h deleted file mode 100644 index b9783477eb..0000000000 --- a/selfdrive/ui/qt/qt_window.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#ifdef __TICI__ -#include -#include -#include -#endif - -#include "system/hardware/hw.h" - -const QString ASSET_PATH = ":/"; -const QSize DEVICE_SCREEN_SIZE = {2160, 1080}; - -void setMainWindow(QWidget *w); diff --git a/selfdrive/ui/qt/request_repeater.cc b/selfdrive/ui/qt/request_repeater.cc deleted file mode 100644 index 7aa731898c..0000000000 --- a/selfdrive/ui/qt/request_repeater.cc +++ /dev/null @@ -1,27 +0,0 @@ -#include "selfdrive/ui/qt/request_repeater.h" - -RequestRepeater::RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey, - int period, bool while_onroad) : HttpRequest(parent) { - timer = new QTimer(this); - timer->setTimerType(Qt::VeryCoarseTimer); - QObject::connect(timer, &QTimer::timeout, [=]() { - if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) { - sendRequest(requestURL); - } - }); - - timer->start(period * 1000); - - if (!cacheKey.isEmpty()) { - prevResp = QString::fromStdString(params.get(cacheKey.toStdString())); - if (!prevResp.isEmpty()) { - QTimer::singleShot(500, [=]() { emit requestDone(prevResp, true, QNetworkReply::NoError); }); - } - QObject::connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) { - if (success && resp != prevResp) { - params.put(cacheKey.toStdString(), resp.toStdString()); - prevResp = resp; - } - }); - } -} diff --git a/selfdrive/ui/qt/request_repeater.h b/selfdrive/ui/qt/request_repeater.h deleted file mode 100644 index c0e2758273..0000000000 --- a/selfdrive/ui/qt/request_repeater.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "common/util.h" -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/ui.h" - -class RequestRepeater : public HttpRequest { -public: - RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool while_onroad=false); - -private: - Params params; - QTimer *timer; - QString prevResp; -}; diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc deleted file mode 100644 index e9c6a2f7c0..0000000000 --- a/selfdrive/ui/qt/sidebar.cc +++ /dev/null @@ -1,165 +0,0 @@ -#include "selfdrive/ui/qt/sidebar.h" - -#include - -#include "selfdrive/ui/qt/util.h" - -void Sidebar::drawMetric(QPainter &p, const QPair &label, QColor c, int y) { - const QRect rect = {30, y, 240, 126}; - - p.setPen(Qt::NoPen); - p.setBrush(QBrush(c)); - p.setClipRect(rect.x() + 4, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip); - p.drawRoundedRect(QRect(rect.x() + 4, rect.y() + 4, 100, 118), 18, 18); - p.setClipping(false); - - QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55)); - pen.setWidth(2); - p.setPen(pen); - p.setBrush(Qt::NoBrush); - p.drawRoundedRect(rect, 20, 20); - - p.setPen(QColor(0xff, 0xff, 0xff)); - p.setFont(InterFont(35, QFont::DemiBold)); - p.drawText(rect.adjusted(22, 0, 0, 0), Qt::AlignCenter, label.first + "\n" + label.second); -} - -Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed(false), settings_pressed(false), mic_indicator_pressed(false) { - home_img = loadPixmap("../assets/images/button_home.png", home_btn.size()); - flag_img = loadPixmap("../assets/images/button_flag.png", home_btn.size()); - settings_img = loadPixmap("../assets/images/button_settings.png", settings_btn.size(), Qt::IgnoreAspectRatio); - mic_img = loadPixmap("../assets/icons/microphone.png", QSize(30, 30)); - link_img = loadPixmap("../assets/icons/link.png", QSize(60, 60)); - - connect(this, &Sidebar::valueChanged, [=] { update(); }); - - setAttribute(Qt::WA_OpaquePaintEvent); - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); - setFixedWidth(300); - - QObject::connect(uiState(), &UIState::uiUpdate, this, &Sidebar::updateState); - - pm = std::make_unique(std::vector{"bookmarkButton"}); -} - -void Sidebar::mousePressEvent(QMouseEvent *event) { - if (onroad && home_btn.contains(event->pos())) { - flag_pressed = true; - update(); - } else if (settings_btn.contains(event->pos())) { - settings_pressed = true; - update(); - } else if (recording_audio && mic_indicator_btn.contains(event->pos())) { - mic_indicator_pressed = true; - update(); - } -} - -void Sidebar::mouseReleaseEvent(QMouseEvent *event) { - if (flag_pressed || settings_pressed || mic_indicator_pressed) { - flag_pressed = settings_pressed = mic_indicator_pressed = false; - update(); - } - if (onroad && home_btn.contains(event->pos())) { - MessageBuilder msg; - msg.initEvent().initBookmarkButton(); - pm->send("bookmarkButton", msg); - } else if (settings_btn.contains(event->pos())) { - emit openSettings(); - } else if (recording_audio && mic_indicator_btn.contains(event->pos())) { - emit openSettings(2, "RecordAudio"); - } -} - -void Sidebar::offroadTransition(bool offroad) { - onroad = !offroad; - update(); -} - -void Sidebar::updateState(const UIState &s) { - if (!isVisible()) return; - - auto &sm = *(s.sm); - - networking = networking ? networking : window()->findChild(""); - bool tethering_on = networking && networking->wifi->tethering_on; - auto deviceState = sm["deviceState"].getDeviceState(); - setProperty("netType", tethering_on ? "Hotspot": network_type[deviceState.getNetworkType()]); - int strength = tethering_on ? 4 : (int)deviceState.getNetworkStrength(); - setProperty("netStrength", strength > 0 ? strength + 1 : 0); - - ItemStatus connectStatus; - auto last_ping = deviceState.getLastAthenaPingTime(); - if (last_ping == 0) { - connectStatus = ItemStatus{{tr("CONNECT"), tr("OFFLINE")}, warning_color}; - } else { - connectStatus = nanos_since_boot() - last_ping < 80e9 - ? ItemStatus{{tr("CONNECT"), tr("ONLINE")}, good_color} - : ItemStatus{{tr("CONNECT"), tr("ERROR")}, danger_color}; - } - setProperty("connectStatus", QVariant::fromValue(connectStatus)); - - ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color}; - auto ts = deviceState.getThermalStatus(); - if (ts == cereal::DeviceState::ThermalStatus::GREEN) { - tempStatus = {{tr("TEMP"), tr("GOOD")}, good_color}; - } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { - tempStatus = {{tr("TEMP"), tr("OK")}, warning_color}; - } - setProperty("tempStatus", QVariant::fromValue(tempStatus)); - - ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, good_color}; - if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) { - pandaStatus = {{tr("NO"), tr("PANDA")}, danger_color}; - } - setProperty("pandaStatus", QVariant::fromValue(pandaStatus)); - - setProperty("recordingAudio", s.scene.recording_audio); -} - -void Sidebar::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing); - - p.fillRect(rect(), QColor(57, 57, 57)); - - // buttons - p.setOpacity(settings_pressed ? 0.65 : 1.0); - p.drawPixmap(settings_btn.x(), settings_btn.y(), settings_img); - p.setOpacity(onroad && flag_pressed ? 0.65 : 1.0); - p.drawPixmap(home_btn.x(), home_btn.y(), onroad ? flag_img : home_img); - if (recording_audio) { - p.setBrush(danger_color); - p.setOpacity(mic_indicator_pressed ? 0.65 : 1.0); - p.drawRoundedRect(mic_indicator_btn, mic_indicator_btn.height() / 2, mic_indicator_btn.height() / 2); - int icon_x = mic_indicator_btn.x() + (mic_indicator_btn.width() - mic_img.width()) / 2; - int icon_y = mic_indicator_btn.y() + (mic_indicator_btn.height() - mic_img.height()) / 2; - p.drawPixmap(icon_x, icon_y, mic_img); - } - p.setOpacity(1.0); - - // network - int x = 58; - const QColor gray(0x54, 0x54, 0x54); - for (int i = 0; i < 5; ++i) { - p.setBrush(i < net_strength ? Qt::white : gray); - p.drawEllipse(x, 196, 27, 27); - x += 37; - } - - p.setFont(InterFont(35)); - p.setPen(QColor(0xff, 0xff, 0xff)); - const QRect r = QRect(58, 247, width() - 100, 50); - - if (net_type == "Hotspot") { - p.drawPixmap(r.x(), r.y() + (r.height() - link_img.height()) / 2, link_img); - } else { - p.drawText(r, Qt::AlignLeft | Qt::AlignVCenter, net_type); - } - - // metrics - drawMetric(p, temp_status.first, temp_status.second, 338); - drawMetric(p, panda_status.first, panda_status.second, 496); - drawMetric(p, connect_status.first, connect_status.second, 654); -} diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h deleted file mode 100644 index 6a2b7b6951..0000000000 --- a/selfdrive/ui/qt/sidebar.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/network/networking.h" - -typedef QPair, QColor> ItemStatus; -Q_DECLARE_METATYPE(ItemStatus); - -class Sidebar : public QFrame { - Q_OBJECT - Q_PROPERTY(ItemStatus connectStatus MEMBER connect_status NOTIFY valueChanged); - Q_PROPERTY(ItemStatus pandaStatus MEMBER panda_status NOTIFY valueChanged); - Q_PROPERTY(ItemStatus tempStatus MEMBER temp_status NOTIFY valueChanged); - Q_PROPERTY(QString netType MEMBER net_type NOTIFY valueChanged); - Q_PROPERTY(int netStrength MEMBER net_strength NOTIFY valueChanged); - Q_PROPERTY(bool recordingAudio MEMBER recording_audio NOTIFY valueChanged); - -public: - explicit Sidebar(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString ¶m = ""); - void valueChanged(); - -public slots: - void offroadTransition(bool offroad); - void updateState(const UIState &s); - -protected: - void paintEvent(QPaintEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void drawMetric(QPainter &p, const QPair &label, QColor c, int y); - - QPixmap home_img, flag_img, settings_img, mic_img, link_img; - bool onroad, recording_audio, flag_pressed, settings_pressed, mic_indicator_pressed; - const QMap network_type = { - {cereal::DeviceState::NetworkType::NONE, tr("--")}, - {cereal::DeviceState::NetworkType::WIFI, tr("Wi-Fi")}, - {cereal::DeviceState::NetworkType::ETHERNET, tr("ETH")}, - {cereal::DeviceState::NetworkType::CELL2_G, tr("2G")}, - {cereal::DeviceState::NetworkType::CELL3_G, tr("3G")}, - {cereal::DeviceState::NetworkType::CELL4_G, tr("LTE")}, - {cereal::DeviceState::NetworkType::CELL5_G, tr("5G")} - }; - - const QRect home_btn = QRect(60, 860, 180, 180); - const QRect settings_btn = QRect(50, 35, 200, 117); - const QRect mic_indicator_btn = QRect(158, 252, 75, 40); - const QColor good_color = QColor(255, 255, 255); - const QColor warning_color = QColor(218, 202, 37); - const QColor danger_color = QColor(201, 34, 49); - - ItemStatus connect_status, panda_status, temp_status; - QString net_type; - int net_strength = 0; - -private: - std::unique_ptr pm; - Networking *networking = nullptr; -}; diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc deleted file mode 100644 index 493c203977..0000000000 --- a/selfdrive/ui/qt/util.cc +++ /dev/null @@ -1,228 +0,0 @@ -#include "selfdrive/ui/qt/util.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common/swaglog.h" -#include "common/util.h" -#include "system/hardware/hw.h" - -QString getVersion() { - static QString version = QString::fromStdString(Params().get("Version")); - return version; -} - -QString getBrand() { - return QObject::tr("openpilot"); -} - -QString getUserAgent() { - return "openpilot-" + getVersion(); -} - -std::optional getDongleId() { - std::string id = Params().get("DongleId"); - - if (!id.empty() && (id != "UnregisteredDevice")) { - return QString::fromStdString(id); - } else { - return {}; - } -} - -QMap getSupportedLanguages() { - QFile f(":/languages.json"); - f.open(QIODevice::ReadOnly | QIODevice::Text); - QString val = f.readAll(); - - QJsonObject obj = QJsonDocument::fromJson(val.toUtf8()).object(); - QMap map; - for (auto key : obj.keys()) { - map[key] = obj[key].toString(); - } - return map; -} - -QString timeAgo(const QDateTime &date) { - if (!util::system_time_valid()) { - return date.date().toString(); - } - - int diff = date.secsTo(QDateTime::currentDateTimeUtc()); - - QString s; - if (diff < 60) { - s = QObject::tr("now"); - } else if (diff < 60 * 60) { - int minutes = diff / 60; - s = QObject::tr("%n minute(s) ago", "", minutes); - } else if (diff < 60 * 60 * 24) { - int hours = diff / (60 * 60); - s = QObject::tr("%n hour(s) ago", "", hours); - } else if (diff < 3600 * 24 * 7) { - int days = diff / (60 * 60 * 24); - s = QObject::tr("%n day(s) ago", "", days); - } else { - s = date.date().toString(); - } - - return s; -} - -void setQtSurfaceFormat() { - QSurfaceFormat fmt; -#ifdef __APPLE__ - fmt.setVersion(3, 2); - fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - fmt.setRenderableType(QSurfaceFormat::OpenGL); -#else - fmt.setRenderableType(QSurfaceFormat::OpenGLES); -#endif - fmt.setSamples(16); - fmt.setStencilBufferSize(1); - QSurfaceFormat::setDefaultFormat(fmt); -} - -void sigTermHandler(int s) { - std::signal(s, SIG_DFL); - qApp->quit(); -} - -void initApp(int argc, char *argv[], bool disable_hidpi) { - Hardware::set_display_power(true); - Hardware::set_brightness(65); - - // setup signal handlers to exit gracefully - std::signal(SIGINT, sigTermHandler); - std::signal(SIGTERM, sigTermHandler); - - QString app_dir; -#ifdef __APPLE__ - // Get the devicePixelRatio, and scale accordingly to maintain 1:1 rendering - QApplication tmp(argc, argv); - app_dir = QCoreApplication::applicationDirPath(); - if (disable_hidpi) { - qputenv("QT_SCALE_FACTOR", QString::number(1.0 / tmp.devicePixelRatio()).toLocal8Bit()); - } -#else - app_dir = QFileInfo(util::readlink("/proc/self/exe").c_str()).path(); -#endif - - qputenv("QT_DBL_CLICK_DIST", QByteArray::number(150)); - // ensure the current dir matches the exectuable's directory - QDir::setCurrent(app_dir); - - setQtSurfaceFormat(); -} - -void swagLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - static std::map levels = { - {QtMsgType::QtDebugMsg, CLOUDLOG_DEBUG}, - {QtMsgType::QtInfoMsg, CLOUDLOG_INFO}, - {QtMsgType::QtWarningMsg, CLOUDLOG_WARNING}, - {QtMsgType::QtCriticalMsg, CLOUDLOG_ERROR}, - {QtMsgType::QtSystemMsg, CLOUDLOG_ERROR}, - {QtMsgType::QtFatalMsg, CLOUDLOG_CRITICAL}, - }; - - std::string file, function; - if (context.file != nullptr) file = context.file; - if (context.function != nullptr) function = context.function; - - auto bts = msg.toUtf8(); - cloudlog_e(levels[type], file.c_str(), context.line, function.c_str(), "%s", bts.constData()); -} - - -QWidget* topWidget(QWidget* widget) { - while (widget->parentWidget() != nullptr) widget=widget->parentWidget(); - return widget; -} - -QPixmap loadPixmap(const QString &fileName, const QSize &size, Qt::AspectRatioMode aspectRatioMode) { - if (size.isEmpty()) { - return QPixmap(fileName); - } else { - return QPixmap(fileName).scaled(size, aspectRatioMode, Qt::SmoothTransformation); - } -} - -static QHash load_bootstrap_icons() { - QHash icons; - - QFile f(":/bootstrap-icons.svg"); - if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { - QDomDocument xml; - xml.setContent(&f); - QDomNode n = xml.documentElement().firstChild(); - while (!n.isNull()) { - QDomElement e = n.toElement(); - if (!e.isNull() && e.hasAttribute("id")) { - QString svg_str; - QTextStream stream(&svg_str); - n.save(stream, 0); - svg_str.replace("", ""); - icons[e.attribute("id")] = svg_str.toUtf8(); - } - n = n.nextSibling(); - } - } - return icons; -} - -QPixmap bootstrapPixmap(const QString &id) { - static QHash icons = load_bootstrap_icons(); - - QPixmap pixmap; - if (auto it = icons.find(id); it != icons.end()) { - pixmap.loadFromData(it.value(), "svg"); - } - return pixmap; -} - -bool hasLongitudinalControl(const cereal::CarParams::Reader &car_params) { - // Using the experimental longitudinal toggle, returns whether longitudinal control - // will be active without needing a restart of openpilot - return car_params.getAlphaLongitudinalAvailable() - ? Params().getBool("AlphaLongitudinalEnabled") - : car_params.getOpenpilotLongitudinalControl(); -} - -// ParamWatcher - -ParamWatcher::ParamWatcher(QObject *parent) : QObject(parent) { - watcher = new QFileSystemWatcher(this); - QObject::connect(watcher, &QFileSystemWatcher::fileChanged, this, &ParamWatcher::fileChanged); -} - -void ParamWatcher::fileChanged(const QString &path) { - auto param_name = QFileInfo(path).fileName(); - auto param_value = QString::fromStdString(params.get(param_name.toStdString())); - - auto it = params_hash.find(param_name); - bool content_changed = (it == params_hash.end()) || (it.value() != param_value); - params_hash[param_name] = param_value; - // emit signal when the content changes. - if (content_changed) { - emit paramChanged(param_name, param_value); - } -} - -void ParamWatcher::addParam(const QString ¶m_name) { - watcher->addPath(QString::fromStdString(params.getParamPath(param_name.toStdString()))); -} diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h deleted file mode 100644 index 2bf1a70a62..0000000000 --- a/selfdrive/ui/qt/util.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "cereal/gen/cpp/car.capnp.h" -#include "common/params.h" - -QString getVersion(); -QString getBrand(); -QString getUserAgent(); -std::optional getDongleId(); -QMap getSupportedLanguages(); -void setQtSurfaceFormat(); -void sigTermHandler(int s); -QString timeAgo(const QDateTime &date); -void swagLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); -void initApp(int argc, char *argv[], bool disable_hidpi = true); -QWidget* topWidget(QWidget* widget); -QPixmap loadPixmap(const QString &fileName, const QSize &size = {}, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio); -QPixmap bootstrapPixmap(const QString &id); -bool hasLongitudinalControl(const cereal::CarParams::Reader &car_params); - -struct InterFont : public QFont { - InterFont(int pixel_size, QFont::Weight weight = QFont::Normal) : QFont("Inter") { - setPixelSize(pixel_size); - setWeight(weight); - } -}; - -class ParamWatcher : public QObject { - Q_OBJECT - -public: - ParamWatcher(QObject *parent); - void addParam(const QString ¶m_name); - -signals: - void paramChanged(const QString ¶m_name, const QString ¶m_value); - -private: - void fileChanged(const QString &path); - - QFileSystemWatcher *watcher; - QHash params_hash; - Params params; -}; diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc deleted file mode 100644 index 5f533cd090..0000000000 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ /dev/null @@ -1,365 +0,0 @@ -#include "selfdrive/ui/qt/widgets/cameraview.h" - -#ifdef __APPLE__ -#include -#else -#include -#endif - -#include -#include - -namespace { - -const char frame_vertex_shader[] = -#ifdef __APPLE__ - "#version 330 core\n" -#else - "#version 300 es\n" -#endif - "layout(location = 0) in vec4 aPosition;\n" - "layout(location = 1) in vec2 aTexCoord;\n" - "uniform mat4 uTransform;\n" - "out vec2 vTexCoord;\n" - "void main() {\n" - " gl_Position = uTransform * aPosition;\n" - " vTexCoord = aTexCoord;\n" - "}\n"; - -const char frame_fragment_shader[] = -#ifdef __TICI__ - "#version 300 es\n" - "#extension GL_OES_EGL_image_external_essl3 : enable\n" - "precision mediump float;\n" - "uniform samplerExternalOES uTexture;\n" - "in vec2 vTexCoord;\n" - "out vec4 colorOut;\n" - "void main() {\n" - " colorOut = texture(uTexture, vTexCoord);\n" - // gamma to improve worst case visibility when dark - " colorOut.rgb = pow(colorOut.rgb, vec3(1.0/1.28));\n" - "}\n"; -#else -#ifdef __APPLE__ - "#version 330 core\n" -#else - "#version 300 es\n" - "precision mediump float;\n" -#endif - "uniform sampler2D uTextureY;\n" - "uniform sampler2D uTextureUV;\n" - "in vec2 vTexCoord;\n" - "out vec4 colorOut;\n" - "void main() {\n" - " float y = texture(uTextureY, vTexCoord).r;\n" - " vec2 uv = texture(uTextureUV, vTexCoord).rg - 0.5;\n" - " float r = y + 1.402 * uv.y;\n" - " float g = y - 0.344 * uv.x - 0.714 * uv.y;\n" - " float b = y + 1.772 * uv.x;\n" - " colorOut = vec4(r, g, b, 1.0);\n" - "}\n"; -#endif - -} // namespace - -CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, QWidget* parent) : - stream_name(stream_name), active_stream_type(type), requested_stream_type(type), QOpenGLWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent); - qRegisterMetaType>("availableStreams"); - QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); - QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); - QObject::connect(this, &CameraWidget::vipcAvailableStreamsUpdated, this, &CameraWidget::availableStreamsUpdated, Qt::QueuedConnection); - QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, this, &CameraWidget::stopVipcThread); -} - -CameraWidget::~CameraWidget() { - makeCurrent(); - stopVipcThread(); - if (isValid()) { - glDeleteVertexArrays(1, &frame_vao); - glDeleteBuffers(1, &frame_vbo); - glDeleteBuffers(1, &frame_ibo); -#ifndef __TICI__ - glDeleteTextures(2, textures); -#endif - } - doneCurrent(); -} - -// Qt uses device-independent pixels, depending on platform this may be -// different to what OpenGL uses -int CameraWidget::glWidth() { - return width() * devicePixelRatio(); -} - -int CameraWidget::glHeight() { - return height() * devicePixelRatio(); -} - -void CameraWidget::initializeGL() { - initializeOpenGLFunctions(); - - program = std::make_unique(context()); - bool ret = program->addShaderFromSourceCode(QOpenGLShader::Vertex, frame_vertex_shader); - assert(ret); - ret = program->addShaderFromSourceCode(QOpenGLShader::Fragment, frame_fragment_shader); - assert(ret); - - program->link(); - GLint frame_pos_loc = program->attributeLocation("aPosition"); - GLint frame_texcoord_loc = program->attributeLocation("aTexCoord"); - - auto [x1, x2, y1, y2] = requested_stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); - const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; - const float frame_coords[4][4] = { - {-1.0, -1.0, x2, y1}, // bl - {-1.0, 1.0, x2, y2}, // tl - { 1.0, 1.0, x1, y2}, // tr - { 1.0, -1.0, x1, y1}, // br - }; - - glGenVertexArrays(1, &frame_vao); - glBindVertexArray(frame_vao); - glGenBuffers(1, &frame_vbo); - glBindBuffer(GL_ARRAY_BUFFER, frame_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(frame_coords), frame_coords, GL_STATIC_DRAW); - glEnableVertexAttribArray(frame_pos_loc); - glVertexAttribPointer(frame_pos_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)0); - glEnableVertexAttribArray(frame_texcoord_loc); - glVertexAttribPointer(frame_texcoord_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)(sizeof(float) * 2)); - glGenBuffers(1, &frame_ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, frame_ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frame_indicies), frame_indicies, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - glUseProgram(program->programId()); - -#ifdef __TICI__ - glUniform1i(program->uniformLocation("uTexture"), 0); -#else - glGenTextures(2, textures); - glUniform1i(program->uniformLocation("uTextureY"), 0); - glUniform1i(program->uniformLocation("uTextureUV"), 1); -#endif -} - -void CameraWidget::showEvent(QShowEvent *event) { - if (!vipc_thread) { - clearFrames(); - vipc_thread = new QThread(); - connect(vipc_thread, &QThread::started, [=]() { vipcThread(); }); - connect(vipc_thread, &QThread::finished, vipc_thread, &QObject::deleteLater); - vipc_thread->start(); - } -} - -void CameraWidget::stopVipcThread() { - makeCurrent(); - if (vipc_thread) { - vipc_thread->requestInterruption(); - vipc_thread->quit(); - vipc_thread->wait(); - vipc_thread = nullptr; - } - -#ifdef __TICI__ - EGLDisplay egl_display = eglGetCurrentDisplay(); - assert(egl_display != EGL_NO_DISPLAY); - for (auto &pair : egl_images) { - eglDestroyImageKHR(egl_display, pair.second); - assert(eglGetError() == EGL_SUCCESS); - } - egl_images.clear(); -#endif -} - -void CameraWidget::availableStreamsUpdated(std::set streams) { - available_streams = streams; -} - -mat4 CameraWidget::calcFrameMatrix() { - // Scale the frame to fit the widget while maintaining the aspect ratio. - float widget_aspect_ratio = (float)width() / height(); - float frame_aspect_ratio = (float)stream_width / stream_height; - float zx = std::min(frame_aspect_ratio / widget_aspect_ratio, 1.0f); - float zy = std::min(widget_aspect_ratio / frame_aspect_ratio, 1.0f); - - return mat4{{ - zx, 0.0, 0.0, 0.0, - 0.0, zy, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }}; -} - -void CameraWidget::paintGL() { - glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - std::lock_guard lk(frame_lock); - if (frames.empty()) return; - - int frame_idx = frames.size() - 1; - - // Always draw latest frame until sync logic is more stable - // for (frame_idx = 0; frame_idx < frames.size() - 1; frame_idx++) { - // if (frames[frame_idx].first == draw_frame_id) break; - // } - - // Log duplicate/dropped frames - if (frames[frame_idx].first == prev_frame_id) { - qDebug() << "Drawing same frame twice" << frames[frame_idx].first; - } else if (frames[frame_idx].first != prev_frame_id + 1) { - qDebug() << "Skipped frame" << frames[frame_idx].first; - } - prev_frame_id = frames[frame_idx].first; - VisionBuf *frame = frames[frame_idx].second; - assert(frame != nullptr); - - auto frame_mat = calcFrameMatrix(); - - glViewport(0, 0, glWidth(), glHeight()); - glBindVertexArray(frame_vao); - glUseProgram(program->programId()); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - -#ifdef __TICI__ - // no frame copy - glActiveTexture(GL_TEXTURE0); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_images[frame->idx]); - assert(glGetError() == GL_NO_ERROR); -#else - // fallback to copy - glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures[0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width, stream_height, GL_RED, GL_UNSIGNED_BYTE, frame->y); - assert(glGetError() == GL_NO_ERROR); - - glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride/2); - glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(GL_TEXTURE_2D, textures[1]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width/2, stream_height/2, GL_RG, GL_UNSIGNED_BYTE, frame->uv); - assert(glGetError() == GL_NO_ERROR); -#endif - - glUniformMatrix4fv(program->uniformLocation("uTransform"), 1, GL_TRUE, frame_mat.v); - glEnableVertexAttribArray(0); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void *)0); - glDisableVertexAttribArray(0); - glBindVertexArray(0); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); -} - -void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { - makeCurrent(); - stream_width = vipc_client->buffers[0].width; - stream_height = vipc_client->buffers[0].height; - stream_stride = vipc_client->buffers[0].stride; - -#ifdef __TICI__ - EGLDisplay egl_display = eglGetCurrentDisplay(); - assert(egl_display != EGL_NO_DISPLAY); - for (auto &pair : egl_images) { - eglDestroyImageKHR(egl_display, pair.second); - } - egl_images.clear(); - - for (int i = 0; i < vipc_client->num_buffers; i++) { // import buffers into OpenGL - int fd = dup(vipc_client->buffers[i].fd); // eglDestroyImageKHR will close, so duplicate - EGLint img_attrs[] = { - EGL_WIDTH, (int)vipc_client->buffers[i].width, - EGL_HEIGHT, (int)vipc_client->buffers[i].height, - EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_NV12, - EGL_DMA_BUF_PLANE0_FD_EXT, fd, - EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, - EGL_DMA_BUF_PLANE0_PITCH_EXT, (int)vipc_client->buffers[i].stride, - EGL_DMA_BUF_PLANE1_FD_EXT, fd, - EGL_DMA_BUF_PLANE1_OFFSET_EXT, (int)vipc_client->buffers[i].uv_offset, - EGL_DMA_BUF_PLANE1_PITCH_EXT, (int)vipc_client->buffers[i].stride, - EGL_NONE - }; - egl_images[i] = eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, 0, img_attrs); - assert(eglGetError() == EGL_SUCCESS); - } -#else - glBindTexture(GL_TEXTURE_2D, textures[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, stream_width, stream_height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr); - assert(glGetError() == GL_NO_ERROR); - - glBindTexture(GL_TEXTURE_2D, textures[1]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, stream_width/2, stream_height/2, 0, GL_RG, GL_UNSIGNED_BYTE, nullptr); - assert(glGetError() == GL_NO_ERROR); -#endif -} - -void CameraWidget::vipcFrameReceived() { - update(); -} - -void CameraWidget::vipcThread() { - VisionStreamType cur_stream = requested_stream_type; - std::unique_ptr vipc_client; - VisionIpcBufExtra meta_main = {0}; - - while (!QThread::currentThread()->isInterruptionRequested()) { - if (!vipc_client || cur_stream != requested_stream_type) { - clearFrames(); - qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; - cur_stream = requested_stream_type; - vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); - } - active_stream_type = cur_stream; - - if (!vipc_client->connected) { - clearFrames(); - auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); - if (streams.empty()) { - QThread::msleep(100); - continue; - } - emit vipcAvailableStreamsUpdated(streams); - - if (!vipc_client->connect(false)) { - QThread::msleep(100); - continue; - } - emit vipcThreadConnected(vipc_client.get()); - } - - if (VisionBuf *buf = vipc_client->recv(&meta_main, 1000)) { - { - std::lock_guard lk(frame_lock); - frames.push_back(std::make_pair(meta_main.frame_id, buf)); - while (frames.size() > FRAME_BUFFER_SIZE) { - frames.pop_front(); - } - } - emit vipcThreadFrameReceived(); - } else { - if (!isVisible()) { - vipc_client->connected = false; - } - } - } -} - -void CameraWidget::clearFrames() { - std::lock_guard lk(frame_lock); - frames.clear(); - available_streams.clear(); -} diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h deleted file mode 100644 index 598603a08a..0000000000 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef __TICI__ -#define EGL_EGLEXT_PROTOTYPES -#define EGL_NO_X11 -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 -#include -#include -#include -#endif - -#include "msgq/visionipc/visionipc_client.h" -#include "selfdrive/ui/ui.h" - -const int FRAME_BUFFER_SIZE = 5; - -class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions { - Q_OBJECT - -public: - using QOpenGLWidget::QOpenGLWidget; - explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, QWidget* parent = nullptr); - ~CameraWidget(); - void setBackgroundColor(const QColor &color) { bg = color; } - void setFrameId(int frame_id) { draw_frame_id = frame_id; } - void setStreamType(VisionStreamType type) { requested_stream_type = type; } - VisionStreamType getStreamType() { return active_stream_type; } - void stopVipcThread(); - -signals: - void clicked(); - void vipcThreadConnected(VisionIpcClient *); - void vipcThreadFrameReceived(); - void vipcAvailableStreamsUpdated(std::set); - -protected: - void paintGL() override; - void initializeGL() override; - void showEvent(QShowEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override { emit clicked(); } - virtual mat4 calcFrameMatrix(); - void vipcThread(); - void clearFrames(); - - int glWidth(); - int glHeight(); - - GLuint frame_vao, frame_vbo, frame_ibo; - GLuint textures[2]; - std::unique_ptr program; - QColor bg = QColor("#000000"); - -#ifdef __TICI__ - std::map egl_images; -#endif - - std::string stream_name; - int stream_width = 0; - int stream_height = 0; - int stream_stride = 0; - std::atomic active_stream_type; - std::atomic requested_stream_type; - std::set available_streams; - QThread *vipc_thread = nullptr; - std::recursive_mutex frame_lock; - std::deque> frames; - uint32_t draw_frame_id = 0; - uint32_t prev_frame_id = 0; - -protected slots: - void vipcConnected(VisionIpcClient *vipc_client); - void vipcFrameReceived(); - void availableStreamsUpdated(std::set streams); -}; - -Q_DECLARE_METATYPE(std::set); diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc deleted file mode 100644 index 40dda971f5..0000000000 --- a/selfdrive/ui/qt/widgets/controls.cc +++ /dev/null @@ -1,141 +0,0 @@ -#include "selfdrive/ui/qt/widgets/controls.h" - -#include -#include - -AbstractControl::AbstractControl(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - - hlayout = new QHBoxLayout; - hlayout->setMargin(0); - hlayout->setSpacing(20); - - // left icon - icon_label = new QLabel(this); - hlayout->addWidget(icon_label); - if (!icon.isEmpty()) { - icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); - icon_label->setPixmap(icon_pixmap); - icon_label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - } - icon_label->setVisible(!icon.isEmpty()); - - // title - title_label = new QPushButton(title); - title_label->setFixedHeight(120); - title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; border: none;"); - hlayout->addWidget(title_label, 1); - - // value next to control button - value = new ElidedLabel(); - value->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - value->setStyleSheet("color: #aaaaaa"); - hlayout->addWidget(value); - - main_layout->addLayout(hlayout); - - // description - description = new QLabel(desc); - description->setContentsMargins(40, 20, 40, 20); - description->setStyleSheet("font-size: 40px; color: grey"); - description->setWordWrap(true); - description->setVisible(false); - main_layout->addWidget(description); - - connect(title_label, &QPushButton::clicked, [=]() { - if (!description->isVisible()) { - emit showDescriptionEvent(); - } - - if (!description->text().isEmpty()) { - description->setVisible(!description->isVisible()); - } - }); - - main_layout->addStretch(); -} - -void AbstractControl::hideEvent(QHideEvent *e) { - if (description != nullptr) { - description->hide(); - } -} - -// controls - -ButtonControl::ButtonControl(const QString &title, const QString &text, const QString &desc, QWidget *parent) : AbstractControl(title, desc, "", parent) { - btn.setText(text); - btn.setStyleSheet(R"( - QPushButton { - padding: 0; - border-radius: 50px; - font-size: 35px; - font-weight: 500; - color: #E4E4E4; - background-color: #393939; - } - QPushButton:pressed { - background-color: #4a4a4a; - } - QPushButton:disabled { - color: #33E4E4E4; - } - )"); - btn.setFixedSize(250, 100); - QObject::connect(&btn, &QPushButton::clicked, this, &ButtonControl::clicked); - hlayout->addWidget(&btn); -} - -// ElidedLabel - -ElidedLabel::ElidedLabel(QWidget *parent) : ElidedLabel({}, parent) {} - -ElidedLabel::ElidedLabel(const QString &text, QWidget *parent) : QLabel(text.trimmed(), parent) { - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - setMinimumWidth(1); -} - -void ElidedLabel::resizeEvent(QResizeEvent* event) { - QLabel::resizeEvent(event); - lastText_ = elidedText_ = ""; -} - -void ElidedLabel::paintEvent(QPaintEvent *event) { - const QString curText = text(); - if (curText != lastText_) { - elidedText_ = fontMetrics().elidedText(curText, Qt::ElideRight, contentsRect().width()); - lastText_ = curText; - } - - QPainter painter(this); - drawFrame(&painter); - QStyleOption opt; - opt.initFrom(this); - style()->drawItemText(&painter, contentsRect(), alignment(), opt.palette, isEnabled(), elidedText_, foregroundRole()); -} - -// ParamControl - -ParamControl::ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent) - : ToggleControl(title, desc, icon, false, parent) { - key = param.toStdString(); - QObject::connect(this, &ParamControl::toggleFlipped, this, &ParamControl::toggleClicked); -} - -void ParamControl::toggleClicked(bool state) { - auto do_confirm = [this]() { - QString content("

" + title_label->text() + "


" - "

" + getDescription() + "

"); - return ConfirmationDialog(content, tr("Enable"), tr("Cancel"), true, this).exec(); - }; - - bool confirmed = store_confirm && params.getBool(key + "Confirmed"); - if (!confirm || confirmed || !state || do_confirm()) { - if (store_confirm && state) params.putBool(key + "Confirmed", true); - params.putBool(key, state); - setIcon(state); - } else { - toggle.togglePosition(); - } -} diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h deleted file mode 100644 index 3342de5324..0000000000 --- a/selfdrive/ui/qt/widgets/controls.h +++ /dev/null @@ -1,319 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "common/params.h" -#include "selfdrive/ui/qt/widgets/input.h" -#include "selfdrive/ui/qt/widgets/toggle.h" - -class ElidedLabel : public QLabel { - Q_OBJECT - -public: - explicit ElidedLabel(QWidget *parent = 0); - explicit ElidedLabel(const QString &text, QWidget *parent = 0); - -signals: - void clicked(); - -protected: - void paintEvent(QPaintEvent *event) override; - void resizeEvent(QResizeEvent* event) override; - void mouseReleaseEvent(QMouseEvent *event) override { - if (rect().contains(event->pos())) { - emit clicked(); - } - } - QString lastText_, elidedText_; -}; - - -class AbstractControl : public QFrame { - Q_OBJECT - -public: - void setDescription(const QString &desc) { - if (description) description->setText(desc); - } - - void setTitle(const QString &title) { - title_label->setText(title); - } - - void setValue(const QString &val) { - value->setText(val); - } - - const QString getDescription() { - return description->text(); - } - - QLabel *icon_label; - QPixmap icon_pixmap; - -public slots: - void showDescription() { - description->setVisible(true); - } - -signals: - void showDescriptionEvent(); - -protected: - AbstractControl(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); - void hideEvent(QHideEvent *e) override; - - QHBoxLayout *hlayout; - QPushButton *title_label; - -private: - ElidedLabel *value; - QLabel *description = nullptr; -}; - -// widget to display a value -class LabelControl : public AbstractControl { - Q_OBJECT - -public: - LabelControl(const QString &title, const QString &text = "", const QString &desc = "", QWidget *parent = nullptr) : AbstractControl(title, desc, "", parent) { - label.setText(text); - label.setAlignment(Qt::AlignRight | Qt::AlignVCenter); - hlayout->addWidget(&label); - } - void setText(const QString &text) { label.setText(text); } - -private: - ElidedLabel label; -}; - -// widget for a button with a label -class ButtonControl : public AbstractControl { - Q_OBJECT - -public: - ButtonControl(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr); - inline void setText(const QString &text) { btn.setText(text); } - inline QString text() const { return btn.text(); } - -signals: - void clicked(); - -public slots: - void setEnabled(bool enabled) { btn.setEnabled(enabled); } - -private: - QPushButton btn; -}; - -class ToggleControl : public AbstractControl { - Q_OBJECT - -public: - ToggleControl(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false, QWidget *parent = nullptr) : AbstractControl(title, desc, icon, parent) { - toggle.setFixedSize(150, 100); - if (state) { - toggle.togglePosition(); - } - hlayout->addWidget(&toggle); - QObject::connect(&toggle, &Toggle::stateChanged, this, &ToggleControl::toggleFlipped); - } - - void setEnabled(bool enabled) { - toggle.setEnabled(enabled); - toggle.update(); - } - -signals: - void toggleFlipped(bool state); - -protected: - Toggle toggle; -}; - -// widget to toggle params -class ParamControl : public ToggleControl { - Q_OBJECT - -public: - ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr); - void setConfirmation(bool _confirm, bool _store_confirm) { - confirm = _confirm; - store_confirm = _store_confirm; - } - - void setActiveIcon(const QString &icon) { - active_icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); - } - - void refresh() { - bool state = params.getBool(key); - if (state != toggle.on) { - toggle.togglePosition(); - setIcon(state); - } - } - - void showEvent(QShowEvent *event) override { - refresh(); - } - -private: - void toggleClicked(bool state); - void setIcon(bool state) { - if (state && !active_icon_pixmap.isNull()) { - icon_label->setPixmap(active_icon_pixmap); - } else if (!icon_pixmap.isNull()) { - icon_label->setPixmap(icon_pixmap); - } - } - - std::string key; - Params params; - QPixmap active_icon_pixmap; - bool confirm = false; - bool store_confirm = false; -}; - -class MultiButtonControl : public AbstractControl { - Q_OBJECT -public: - MultiButtonControl(const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts, const int minimum_button_width = 225) : AbstractControl(title, desc, icon) { - const QString style = R"( - QPushButton { - border-radius: 50px; - font-size: 40px; - font-weight: 500; - height:100px; - padding: 0 25 0 25; - color: #E4E4E4; - background-color: #393939; - } - QPushButton:pressed { - background-color: #4a4a4a; - } - QPushButton:checked:enabled { - background-color: #33Ab4C; - } - QPushButton:checked:disabled { - background-color: #9933Ab4C; - } - QPushButton:disabled { - color: #33E4E4E4; - } - )"; - - button_group = new QButtonGroup(this); - button_group->setExclusive(true); - for (int i = 0; i < button_texts.size(); i++) { - QPushButton *button = new QPushButton(button_texts[i], this); - button->setCheckable(true); - button->setChecked(i == 0); - button->setStyleSheet(style); - button->setMinimumWidth(minimum_button_width); - hlayout->addWidget(button); - button_group->addButton(button, i); - } - - QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonClicked), this, &MultiButtonControl::buttonClicked); - } - - void setEnabled(bool enable) { - for (auto btn : button_group->buttons()) { - btn->setEnabled(enable); - } - } - - void setCheckedButton(int id) { - button_group->button(id)->setChecked(true); - } - -signals: - void buttonClicked(int id); - -protected: - QButtonGroup *button_group; -}; - -class ButtonParamControl : public MultiButtonControl { - Q_OBJECT -public: - ButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts, const int minimum_button_width = 225) : MultiButtonControl(title, desc, icon, - button_texts, minimum_button_width) { - key = param.toStdString(); - int value = atoi(params.get(key).c_str()); - - if (value > 0 && value < button_group->buttons().size()) { - button_group->button(value)->setChecked(true); - } - - QObject::connect(this, QOverload::of(&MultiButtonControl::buttonClicked), [=](int id) { - params.put(key, std::to_string(id)); - }); - } - - void refresh() { - int value = atoi(params.get(key).c_str()); - button_group->button(value)->setChecked(true); - } - - void showEvent(QShowEvent *event) override { - refresh(); - } - -private: - std::string key; - Params params; -}; - -class ListWidget : public QWidget { - Q_OBJECT - public: - explicit ListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) { - outer_layout.setMargin(0); - outer_layout.setSpacing(0); - outer_layout.addLayout(&inner_layout); - inner_layout.setMargin(0); - inner_layout.setSpacing(25); // default spacing is 25 - outer_layout.addStretch(1); - } - inline void addItem(QWidget *w) { inner_layout.addWidget(w); } - inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); } - inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); } - -private: - void paintEvent(QPaintEvent *) override { - QPainter p(this); - p.setPen(Qt::gray); - for (int i = 0; i < inner_layout.count() - 1; ++i) { - QWidget *widget = inner_layout.itemAt(i)->widget(); - if (widget == nullptr || widget->isVisible()) { - QRect r = inner_layout.itemAt(i)->geometry(); - int bottom = r.bottom() + inner_layout.spacing() / 2; - p.drawLine(r.left() + 40, bottom, r.right() - 40, bottom); - } - } - } - QVBoxLayout outer_layout; - QVBoxLayout inner_layout; -}; - -// convenience class for wrapping layouts -class LayoutWidget : public QWidget { - Q_OBJECT - -public: - LayoutWidget(QLayout *l, QWidget *parent = nullptr) : QWidget(parent) { - setLayout(l); - } -}; diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc deleted file mode 100644 index 0cbf14931b..0000000000 --- a/selfdrive/ui/qt/widgets/input.cc +++ /dev/null @@ -1,336 +0,0 @@ -#include "selfdrive/ui/qt/widgets/input.h" - -#include -#include - -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - - -DialogBase::DialogBase(QWidget *parent) : QDialog(parent) { - Q_ASSERT(parent != nullptr); - parent->installEventFilter(this); - - setStyleSheet(R"( - * { - outline: none; - color: white; - font-family: Inter; - } - DialogBase { - background-color: black; - } - QPushButton { - height: 160; - font-size: 55px; - font-weight: 400; - border-radius: 10px; - color: white; - background-color: #333333; - } - QPushButton:pressed { - background-color: #444444; - } - )"); -} - -bool DialogBase::eventFilter(QObject *o, QEvent *e) { - if (o == parent() && e->type() == QEvent::Hide) { - reject(); - } - return QDialog::eventFilter(o, e); -} - -int DialogBase::exec() { - setMainWindow(this); - return QDialog::exec(); -} - -InputDialog::InputDialog(const QString &title, QWidget *parent, const QString &subtitle, bool secret) : DialogBase(parent) { - main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 55, 50, 50); - main_layout->setSpacing(0); - - // build header - QHBoxLayout *header_layout = new QHBoxLayout(); - - QVBoxLayout *vlayout = new QVBoxLayout; - header_layout->addLayout(vlayout); - label = new QLabel(title, this); - label->setStyleSheet("font-size: 90px; font-weight: bold;"); - vlayout->addWidget(label, 1, Qt::AlignTop | Qt::AlignLeft); - - if (!subtitle.isEmpty()) { - sublabel = new QLabel(subtitle, this); - sublabel->setStyleSheet("font-size: 55px; font-weight: light; color: #BDBDBD;"); - vlayout->addWidget(sublabel, 1, Qt::AlignTop | Qt::AlignLeft); - } - - QPushButton* cancel_btn = new QPushButton(tr("Cancel")); - cancel_btn->setFixedSize(386, 125); - cancel_btn->setStyleSheet(R"( - QPushButton { - font-size: 48px; - border-radius: 10px; - color: #E4E4E4; - background-color: #333333; - } - QPushButton:pressed { - background-color: #444444; - } - )"); - header_layout->addWidget(cancel_btn, 0, Qt::AlignRight); - QObject::connect(cancel_btn, &QPushButton::clicked, this, &InputDialog::reject); - QObject::connect(cancel_btn, &QPushButton::clicked, this, &InputDialog::cancel); - - main_layout->addLayout(header_layout); - - // text box - main_layout->addStretch(2); - - QWidget *textbox_widget = new QWidget; - textbox_widget->setObjectName("textbox"); - QHBoxLayout *textbox_layout = new QHBoxLayout(textbox_widget); - textbox_layout->setContentsMargins(50, 0, 50, 0); - - textbox_widget->setStyleSheet(R"( - #textbox { - margin-left: 50px; - margin-right: 50px; - border-radius: 0; - border-bottom: 3px solid #BDBDBD; - } - * { - border: none; - font-size: 80px; - font-weight: light; - background-color: transparent; - } - )"); - - line = new QLineEdit(); - line->setStyleSheet("lineedit-password-character: 8226; lineedit-password-mask-delay: 1500;"); - textbox_layout->addWidget(line, 1); - - if (secret) { - eye_btn = new QPushButton(); - eye_btn->setCheckable(true); - eye_btn->setFixedSize(150, 120); - QObject::connect(eye_btn, &QPushButton::toggled, [=](bool checked) { - if (checked) { - eye_btn->setIcon(QIcon(ASSET_PATH + "icons/eye_closed.svg")); - eye_btn->setIconSize(QSize(81, 54)); - line->setEchoMode(QLineEdit::Password); - } else { - eye_btn->setIcon(QIcon(ASSET_PATH + "icons/eye_open.svg")); - eye_btn->setIconSize(QSize(81, 44)); - line->setEchoMode(QLineEdit::Normal); - } - }); - eye_btn->toggle(); - eye_btn->setChecked(false); - textbox_layout->addWidget(eye_btn); - } - - main_layout->addWidget(textbox_widget, 0, Qt::AlignBottom); - main_layout->addSpacing(25); - - k = new Keyboard(this); - QObject::connect(k, &Keyboard::emitEnter, this, &InputDialog::handleEnter); - QObject::connect(k, &Keyboard::emitBackspace, this, [=]() { - line->backspace(); - }); - QObject::connect(k, &Keyboard::emitKey, this, [=](const QString &key) { - line->insert(key.left(1)); - }); - - main_layout->addWidget(k, 2, Qt::AlignBottom); -} - -QString InputDialog::getText(const QString &prompt, QWidget *parent, const QString &subtitle, - bool secret, int minLength, const QString &defaultText) { - InputDialog d(prompt, parent, subtitle, secret); - d.line->setText(defaultText); - d.setMinLength(minLength); - const int ret = d.exec(); - return ret ? d.text() : QString(); -} - -QString InputDialog::text() { - return line->text(); -} - -void InputDialog::show() { - setMainWindow(this); -} - -void InputDialog::handleEnter() { - if (line->text().length() >= minLength) { - done(QDialog::Accepted); - emitText(line->text()); - } else { - setMessage(tr("Need at least %n character(s)!", "", minLength), false); - } -} - -void InputDialog::setMessage(const QString &message, bool clearInputField) { - label->setText(message); - if (clearInputField) { - line->setText(""); - } -} - -void InputDialog::setMinLength(int length) { - minLength = length; -} - -// ConfirmationDialog - -ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, - const bool rich, QWidget *parent) : DialogBase(parent) { - QFrame *container = new QFrame(this); - container->setStyleSheet(R"( - QFrame { background-color: #1B1B1B; color: #C9C9C9; } - #confirm_btn { background-color: #465BEA; } - #confirm_btn:pressed { background-color: #3049F4; } - )"); - QVBoxLayout *main_layout = new QVBoxLayout(container); - main_layout->setContentsMargins(32, rich ? 32 : 120, 32, 32); - - QLabel *prompt = new QLabel(prompt_text, this); - prompt->setWordWrap(true); - prompt->setAlignment(rich ? Qt::AlignLeft : Qt::AlignHCenter); - prompt->setStyleSheet((rich ? "font-size: 42px; font-weight: light;" : "font-size: 70px; font-weight: bold;") + QString(" margin: 45px;")); - main_layout->addWidget(rich ? (QWidget*)new ScrollView(prompt, this) : (QWidget*)prompt, 1, Qt::AlignTop); - - // cancel + confirm buttons - QHBoxLayout *btn_layout = new QHBoxLayout(); - btn_layout->setSpacing(30); - main_layout->addLayout(btn_layout); - - if (cancel_text.length()) { - QPushButton* cancel_btn = new QPushButton(cancel_text); - btn_layout->addWidget(cancel_btn); - QObject::connect(cancel_btn, &QPushButton::clicked, this, &ConfirmationDialog::reject); - } - - if (confirm_text.length()) { - QPushButton* confirm_btn = new QPushButton(confirm_text); - confirm_btn->setObjectName("confirm_btn"); - btn_layout->addWidget(confirm_btn); - QObject::connect(confirm_btn, &QPushButton::clicked, this, &ConfirmationDialog::accept); - } - - QVBoxLayout *outer_layout = new QVBoxLayout(this); - int margin = rich ? 100 : 200; - outer_layout->setContentsMargins(margin, margin, margin, margin); - outer_layout->addWidget(container); -} - -bool ConfirmationDialog::alert(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d(prompt_text, tr("Ok"), "", false, parent); - return d.exec(); -} - -bool ConfirmationDialog::confirm(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { - ConfirmationDialog d(prompt_text, confirm_text, tr("Cancel"), false, parent); - return d.exec(); -} - -bool ConfirmationDialog::rich(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d(prompt_text, tr("Ok"), "", true, parent); - return d.exec(); -} - -// MultiOptionDialog - -MultiOptionDialog::MultiOptionDialog(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent) : DialogBase(parent) { - QFrame *container = new QFrame(this); - container->setStyleSheet(R"( - QFrame { background-color: #1B1B1B; } - #confirm_btn[enabled="false"] { background-color: #2B2B2B; } - #confirm_btn:enabled { background-color: #465BEA; } - #confirm_btn:enabled:pressed { background-color: #3049F4; } - )"); - - QVBoxLayout *main_layout = new QVBoxLayout(container); - main_layout->setContentsMargins(55, 50, 55, 50); - - QLabel *title = new QLabel(prompt_text, this); - title->setStyleSheet("font-size: 70px; font-weight: 500;"); - main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop); - main_layout->addSpacing(25); - - QWidget *listWidget = new QWidget(this); - QVBoxLayout *listLayout = new QVBoxLayout(listWidget); - listLayout->setSpacing(20); - listWidget->setStyleSheet(R"( - QPushButton { - height: 135; - padding: 0px 50px; - text-align: left; - font-size: 55px; - font-weight: 300; - border-radius: 10px; - background-color: #4F4F4F; - } - QPushButton:checked { background-color: #465BEA; } - )"); - - QButtonGroup *group = new QButtonGroup(listWidget); - group->setExclusive(true); - - QPushButton *confirm_btn = new QPushButton(tr("Select")); - confirm_btn->setObjectName("confirm_btn"); - confirm_btn->setEnabled(false); - - for (const QString &s : l) { - QPushButton *selectionLabel = new QPushButton(s); - selectionLabel->setCheckable(true); - selectionLabel->setChecked(s == current); - QObject::connect(selectionLabel, &QPushButton::toggled, [=](bool checked) { - if (checked) selection = s; - if (selection != current) { - confirm_btn->setEnabled(true); - } else { - confirm_btn->setEnabled(false); - } - }); - - group->addButton(selectionLabel); - listLayout->addWidget(selectionLabel); - } - // add stretch to keep buttons spaced correctly - listLayout->addStretch(1); - - ScrollView *scroll_view = new ScrollView(listWidget, this); - scroll_view->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - - main_layout->addWidget(scroll_view); - main_layout->addSpacing(35); - - // cancel + confirm buttons - QHBoxLayout *blayout = new QHBoxLayout; - main_layout->addLayout(blayout); - blayout->setSpacing(50); - - QPushButton *cancel_btn = new QPushButton(tr("Cancel")); - QObject::connect(cancel_btn, &QPushButton::clicked, this, &ConfirmationDialog::reject); - QObject::connect(confirm_btn, &QPushButton::clicked, this, &ConfirmationDialog::accept); - blayout->addWidget(cancel_btn); - blayout->addWidget(confirm_btn); - - QVBoxLayout *outer_layout = new QVBoxLayout(this); - outer_layout->setContentsMargins(50, 50, 50, 50); - outer_layout->addWidget(container); -} - -QString MultiOptionDialog::getSelection(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent) { - MultiOptionDialog d(prompt_text, l, current, parent); - if (d.exec()) { - return d.selection; - } - return ""; -} diff --git a/selfdrive/ui/qt/widgets/input.h b/selfdrive/ui/qt/widgets/input.h deleted file mode 100644 index 089e54e4a0..0000000000 --- a/selfdrive/ui/qt/widgets/input.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "selfdrive/ui/qt/widgets/keyboard.h" - - -class DialogBase : public QDialog { - Q_OBJECT - -protected: - DialogBase(QWidget *parent); - bool eventFilter(QObject *o, QEvent *e) override; - -public slots: - int exec() override; -}; - -class InputDialog : public DialogBase { - Q_OBJECT - -public: - explicit InputDialog(const QString &title, QWidget *parent, const QString &subtitle = "", bool secret = false); - static QString getText(const QString &title, QWidget *parent, const QString &subtitle = "", - bool secret = false, int minLength = -1, const QString &defaultText = ""); - QString text(); - void setMessage(const QString &message, bool clearInputField = true); - void setMinLength(int length); - void show(); - -private: - int minLength; - QLineEdit *line; - Keyboard *k; - QLabel *label; - QLabel *sublabel; - QVBoxLayout *main_layout; - QPushButton *eye_btn; - -private slots: - void handleEnter(); - -signals: - void cancel(); - void emitText(const QString &text); -}; - -class ConfirmationDialog : public DialogBase { - Q_OBJECT - -public: - explicit ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, - const QString &cancel_text, const bool rich, QWidget* parent); - static bool alert(const QString &prompt_text, QWidget *parent); - static bool confirm(const QString &prompt_text, const QString &confirm_text, QWidget *parent); - static bool rich(const QString &prompt_text, QWidget *parent); -}; - -class MultiOptionDialog : public DialogBase { - Q_OBJECT - -public: - explicit MultiOptionDialog(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent); - static QString getSelection(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent); - QString selection; -}; diff --git a/selfdrive/ui/qt/widgets/keyboard.cc b/selfdrive/ui/qt/widgets/keyboard.cc deleted file mode 100644 index 9ead27b8d5..0000000000 --- a/selfdrive/ui/qt/widgets/keyboard.cc +++ /dev/null @@ -1,182 +0,0 @@ -#include "selfdrive/ui/qt/widgets/keyboard.h" - -#include - -#include -#include -#include -#include -#include - -const QString BACKSPACE_KEY = "⌫"; -const QString ENTER_KEY = "→"; -const QString SHIFT_KEY = "⇧"; -const QString CAPS_LOCK_KEY = "⇪"; - -const QMap KEY_STRETCH = {{" ", 3}, {ENTER_KEY, 2}}; - -const QStringList CONTROL_BUTTONS = {SHIFT_KEY, CAPS_LOCK_KEY, "ABC", "#+=", "123", BACKSPACE_KEY, ENTER_KEY}; - -const float key_spacing_vertical = 20; -const float key_spacing_horizontal = 15; - -KeyButton::KeyButton(const QString &text, QWidget *parent) : QPushButton(text, parent) { - setAttribute(Qt::WA_AcceptTouchEvents); - setFocusPolicy(Qt::NoFocus); -} - -bool KeyButton::event(QEvent *event) { - if (event->type() == QEvent::TouchBegin || event->type() == QEvent::TouchEnd) { - QTouchEvent *touchEvent = static_cast(event); - if (!touchEvent->touchPoints().empty()) { - const QEvent::Type mouseType = event->type() == QEvent::TouchBegin ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease; - QMouseEvent mouseEvent(mouseType, touchEvent->touchPoints().front().pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); - QPushButton::event(&mouseEvent); - event->accept(); - parentWidget()->update(); - return true; - } - } - return QPushButton::event(event); -} - -KeyboardLayout::KeyboardLayout(QWidget* parent, const std::vector>& layout) : QWidget(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - main_layout->setSpacing(0); - - QButtonGroup* btn_group = new QButtonGroup(this); - QObject::connect(btn_group, SIGNAL(buttonClicked(QAbstractButton*)), parent, SLOT(handleButton(QAbstractButton*))); - - for (const auto &s : layout) { - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->setSpacing(0); - - if (main_layout->count() == 1) { - hlayout->addSpacing(90); - } - - for (const QString &p : s) { - KeyButton* btn = new KeyButton(p); - if (p == BACKSPACE_KEY) { - btn->setAutoRepeat(true); - } else if (p == ENTER_KEY) { - btn->setStyleSheet(R"( - QPushButton { - background-color: #465BEA; - } - QPushButton:pressed { - background-color: #444444; - } - )"); - } - btn->setFixedHeight(135 + key_spacing_vertical); - btn_group->addButton(btn); - hlayout->addWidget(btn, KEY_STRETCH.value(p, 1)); - } - - if (main_layout->count() == 1) { - hlayout->addSpacing(90); - } - - main_layout->addLayout(hlayout); - } - - setStyleSheet(QString(R"( - QPushButton { - font-size: 75px; - margin-left: %1px; - margin-right: %1px; - margin-top: %2px; - margin-bottom: %2px; - padding: 0px; - border-radius: 10px; - color: #dddddd; - background-color: #444444; - } - QPushButton:pressed { - background-color: #333333; - } - )").arg(key_spacing_vertical / 2).arg(key_spacing_horizontal / 2)); -} - -Keyboard::Keyboard(QWidget *parent) : QFrame(parent) { - main_layout = new QStackedLayout(this); - main_layout->setMargin(0); - - // lowercase - std::vector> lowercase = { - {"q", "w", "e", "r", "t", "y", "u", "i", "o", "p"}, - {"a", "s", "d", "f", "g", "h", "j", "k", "l"}, - {SHIFT_KEY, "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY}, - {"123", "/", "-", " ", ".", ENTER_KEY}, - }; - main_layout->addWidget(new KeyboardLayout(this, lowercase)); - - // uppercase - std::vector> uppercase = { - {"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"}, - {"A", "S", "D", "F", "G", "H", "J", "K", "L"}, - {SHIFT_KEY, "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY}, - {"123", "/", "-", " ", ".", ENTER_KEY}, - }; - main_layout->addWidget(new KeyboardLayout(this, uppercase)); - - // numbers + specials - std::vector> numbers = { - {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}, - {"-", "/", ":", ";", "(", ")", "$", "&&", "@", "\""}, - {"#+=", ".", ",", "?", "!", "`", BACKSPACE_KEY}, - {"ABC", " ", ".", ENTER_KEY}, - }; - main_layout->addWidget(new KeyboardLayout(this, numbers)); - - // extra specials - std::vector> specials = { - {"[", "]", "{", "}", "#", "%", "^", "*", "+", "="}, - {"_", "\\", "|", "~", "<", ">", "€", "£", "¥", "•"}, - {"123", ".", ",", "?", "!", "'", BACKSPACE_KEY}, - {"ABC", " ", ".", ENTER_KEY}, - }; - main_layout->addWidget(new KeyboardLayout(this, specials)); - - main_layout->setCurrentIndex(0); -} - -void Keyboard::handleCapsPress() { - shift_state = (shift_state + 1) % 3; - bool is_uppercase = shift_state > 0; - main_layout->setCurrentIndex(is_uppercase); - - for (KeyButton* btn : main_layout->currentWidget()->findChildren()) { - if (btn->text() == SHIFT_KEY || btn->text() == CAPS_LOCK_KEY) { - btn->setText(shift_state == 2 ? CAPS_LOCK_KEY : SHIFT_KEY); - btn->setStyleSheet(is_uppercase ? "background-color: #465BEA;" : ""); - } - } -} - -void Keyboard::handleButton(QAbstractButton* btn) { - const QString &key = btn->text(); - if (CONTROL_BUTTONS.contains(key)) { - if (key == "ABC" || key == "123" || key == "#+=") { - int index = (key == "ABC") ? 0 : (key == "123" ? 2 : 3); - main_layout->setCurrentIndex(index); - shift_state = 0; - } else if (key == SHIFT_KEY || key == CAPS_LOCK_KEY) { - handleCapsPress(); - } else if (key == ENTER_KEY) { - main_layout->setCurrentIndex(0); - shift_state = 0; - emit emitEnter(); - } else if (key == BACKSPACE_KEY) { - emit emitBackspace(); - } - } else { - if (shift_state == 1 && "A" <= key && key <= "Z") { - main_layout->setCurrentIndex(0); - shift_state = 0; - } - emit emitKey(key); - } -} diff --git a/selfdrive/ui/qt/widgets/keyboard.h b/selfdrive/ui/qt/widgets/keyboard.h deleted file mode 100644 index e61617283a..0000000000 --- a/selfdrive/ui/qt/widgets/keyboard.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -class KeyButton : public QPushButton { - Q_OBJECT - -public: - KeyButton(const QString &text, QWidget *parent = 0); - bool event(QEvent *event) override; -}; - -class KeyboardLayout : public QWidget { - Q_OBJECT - -public: - explicit KeyboardLayout(QWidget* parent, const std::vector>& layout); -}; - -class Keyboard : public QFrame { - Q_OBJECT - -public: - explicit Keyboard(QWidget *parent = 0); - -private: - QStackedLayout* main_layout; - int shift_state = 0; - -private slots: - void handleButton(QAbstractButton* m_button); - void handleCapsPress(); - -signals: - void emitKey(const QString &s); - void emitBackspace(); - void emitEnter(); -}; diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc deleted file mode 100644 index 3a4828a2a8..0000000000 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ /dev/null @@ -1,138 +0,0 @@ -#include "selfdrive/ui/qt/widgets/offroad_alerts.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "common/util.h" -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -AbstractAlert::AbstractAlert(bool hasRebootBtn, QWidget *parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(50); - main_layout->setSpacing(30); - - QWidget *widget = new QWidget; - scrollable_layout = new QVBoxLayout(widget); - widget->setStyleSheet("background-color: transparent;"); - main_layout->addWidget(new ScrollView(widget)); - - // bottom footer, dismiss + reboot buttons - QHBoxLayout *footer_layout = new QHBoxLayout(); - main_layout->addLayout(footer_layout); - - QPushButton *dismiss_btn = new QPushButton(tr("Close")); - dismiss_btn->setFixedSize(400, 125); - footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft); - QObject::connect(dismiss_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss); - - action_btn = new QPushButton(); - action_btn->setVisible(false); - action_btn->setFixedHeight(125); - footer_layout->addWidget(action_btn, 0, Qt::AlignBottom | Qt::AlignRight); - QObject::connect(action_btn, &QPushButton::clicked, [=]() { - if (!alerts["Offroad_ExcessiveActuation"]->text().isEmpty()) { - params.remove("Offroad_ExcessiveActuation"); - } else { - params.putBool("SnoozeUpdate", true); - } - }); - QObject::connect(action_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss); - action_btn->setStyleSheet("color: white; background-color: #4F4F4F; padding-left: 60px; padding-right: 60px;"); - - if (hasRebootBtn) { - QPushButton *rebootBtn = new QPushButton(tr("Reboot and Update")); - rebootBtn->setFixedSize(600, 125); - footer_layout->addWidget(rebootBtn, 0, Qt::AlignBottom | Qt::AlignRight); - QObject::connect(rebootBtn, &QPushButton::clicked, [=]() { Hardware::reboot(); }); - } - - setStyleSheet(R"( - * { - font-size: 48px; - color: white; - } - QFrame { - border-radius: 30px; - background-color: #393939; - } - QPushButton { - color: black; - font-weight: 500; - border-radius: 30px; - background-color: white; - } - )"); -} - -int OffroadAlert::refresh() { - // build widgets for each offroad alert on first refresh - if (alerts.empty()) { - QString json = util::read_file("../selfdrived/alerts_offroad.json").c_str(); - QJsonObject obj = QJsonDocument::fromJson(json.toUtf8()).object(); - - // descending sort labels by severity - std::vector> sorted; - for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) { - sorted.push_back({it.key().toStdString(), it.value()["severity"].toInt()}); - } - std::sort(sorted.begin(), sorted.end(), [=](auto &l, auto &r) { return l.second > r.second; }); - - for (auto &[key, severity] : sorted) { - QLabel *l = new QLabel(this); - alerts[key] = l; - l->setMargin(60); - l->setWordWrap(true); - l->setStyleSheet(QString("background-color: %1").arg(severity ? "#E22C2C" : "#292929")); - scrollable_layout->addWidget(l); - } - scrollable_layout->addStretch(1); - } - - int alertCount = 0; - for (const auto &[key, label] : alerts) { - QString text; - std::string bytes = params.get(key); - if (bytes.size()) { - auto doc_par = QJsonDocument::fromJson(bytes.c_str()); - text = tr(doc_par["text"].toString().toUtf8().data()); - auto extra = doc_par["extra"].toString(); - if (!extra.isEmpty()) { - text = text.arg(extra); - } - } - label->setText(text); - label->setVisible(!text.isEmpty()); - alertCount += !text.isEmpty(); - } - - action_btn->setVisible(!alerts["Offroad_ExcessiveActuation"]->text().isEmpty() || !alerts["Offroad_ConnectivityNeeded"]->text().isEmpty()); - if (!alerts["Offroad_ExcessiveActuation"]->text().isEmpty()) { - action_btn->setText(tr("Acknowledge Excessive Actuation")); - } else { - action_btn->setText(tr("Snooze Update")); - } - - return alertCount; -} - -UpdateAlert::UpdateAlert(QWidget *parent) : AbstractAlert(true, parent) { - releaseNotes = new QLabel(this); - releaseNotes->setWordWrap(true); - releaseNotes->setAlignment(Qt::AlignTop); - scrollable_layout->addWidget(releaseNotes); -} - -bool UpdateAlert::refresh() { - bool updateAvailable = params.getBool("UpdateAvailable"); - if (updateAvailable) { - releaseNotes->setText(params.get("UpdaterNewReleaseNotes").c_str()); - } - return updateAvailable; -} diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.h b/selfdrive/ui/qt/widgets/offroad_alerts.h deleted file mode 100644 index 2dcf4f9d8c..0000000000 --- a/selfdrive/ui/qt/widgets/offroad_alerts.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -#include "common/params.h" - -class AbstractAlert : public QFrame { - Q_OBJECT - -protected: - AbstractAlert(bool hasRebootBtn, QWidget *parent = nullptr); - - QPushButton *action_btn; - QVBoxLayout *scrollable_layout; - Params params; - std::map alerts; - -signals: - void dismiss(); -}; - -class UpdateAlert : public AbstractAlert { - Q_OBJECT - -public: - UpdateAlert(QWidget *parent = 0); - bool refresh(); - -private: - QLabel *releaseNotes = nullptr; -}; - -class OffroadAlert : public AbstractAlert { - Q_OBJECT - -public: - explicit OffroadAlert(QWidget *parent = 0) : AbstractAlert(false, parent) {} - int refresh(); -}; diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc deleted file mode 100644 index ee820c46a3..0000000000 --- a/selfdrive/ui/qt/widgets/prime.cc +++ /dev/null @@ -1,265 +0,0 @@ -#include "selfdrive/ui/qt/widgets/prime.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "selfdrive/ui/qt/request_repeater.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/widgets/wifi.h" - -using qrcodegen::QrCode; - -PairingQRWidget::PairingQRWidget(QWidget* parent) : QWidget(parent) { - timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, &PairingQRWidget::refresh); -} - -void PairingQRWidget::showEvent(QShowEvent *event) { - refresh(); - timer->start(5 * 60 * 1000); - device()->setOffroadBrightness(100); -} - -void PairingQRWidget::hideEvent(QHideEvent *event) { - timer->stop(); - device()->setOffroadBrightness(BACKLIGHT_OFFROAD); -} - -void PairingQRWidget::refresh() { - QString pairToken = CommaApi::create_jwt({{"pair", true}}); - QString qrString = "https://connect.comma.ai/?pair=" + pairToken; - this->updateQrCode(qrString); - update(); -} - -void PairingQRWidget::updateQrCode(const QString &text) { - QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW); - qint32 sz = qr.getSize(); - QImage im(sz, sz, QImage::Format_RGB32); - - QRgb black = qRgb(0, 0, 0); - QRgb white = qRgb(255, 255, 255); - for (int y = 0; y < sz; y++) { - for (int x = 0; x < sz; x++) { - im.setPixel(x, y, qr.getModule(x, y) ? black : white); - } - } - - // Integer division to prevent anti-aliasing - int final_sz = ((width() / sz) - 1) * sz; - img = QPixmap::fromImage(im.scaled(final_sz, final_sz, Qt::KeepAspectRatio), Qt::MonoOnly); -} - -void PairingQRWidget::paintEvent(QPaintEvent *e) { - QPainter p(this); - p.fillRect(rect(), Qt::white); - - QSize s = (size() - img.size()) / 2; - p.drawPixmap(s.width(), s.height(), img); -} - - -PairingPopup::PairingPopup(QWidget *parent) : DialogBase(parent) { - QHBoxLayout *hlayout = new QHBoxLayout(this); - hlayout->setContentsMargins(0, 0, 0, 0); - hlayout->setSpacing(0); - - setStyleSheet("PairingPopup { background-color: #E0E0E0; }"); - - // text - QVBoxLayout *vlayout = new QVBoxLayout(); - vlayout->setContentsMargins(85, 70, 50, 70); - vlayout->setSpacing(50); - hlayout->addLayout(vlayout, 1); - { - QPushButton *close = new QPushButton(QIcon(":/icons/close.svg"), "", this); - close->setIconSize(QSize(80, 80)); - close->setStyleSheet("border: none;"); - vlayout->addWidget(close, 0, Qt::AlignLeft); - QObject::connect(close, &QPushButton::clicked, this, &QDialog::reject); - - vlayout->addSpacing(30); - - QLabel *title = new QLabel(tr("Pair your device to your comma account"), this); - title->setStyleSheet("font-size: 75px; color: black;"); - title->setWordWrap(true); - vlayout->addWidget(title); - - QLabel *instructions = new QLabel(QString(R"( -
    -
  1. %1
  2. -
  3. %2
  4. -
  5. %3
  6. -
- )").arg(tr("Go to https://connect.comma.ai on your phone")) - .arg(tr("Click \"add new device\" and scan the QR code on the right")) - .arg(tr("Bookmark connect.comma.ai to your home screen to use it like an app")), this); - - instructions->setStyleSheet("font-size: 47px; font-weight: bold; color: black;"); - instructions->setWordWrap(true); - vlayout->addWidget(instructions); - - vlayout->addStretch(); - } - - // QR code - PairingQRWidget *qr = new PairingQRWidget(this); - hlayout->addWidget(qr, 1); -} - -int PairingPopup::exec() { - if (!util::system_time_valid()) { - ConfirmationDialog::alert(tr("Please connect to Wi-Fi to complete initial pairing"), parentWidget()); - return QDialog::Rejected; - } - return DialogBase::exec(); -} - - -PrimeUserWidget::PrimeUserWidget(QWidget *parent) : QFrame(parent) { - setObjectName("primeWidget"); - QVBoxLayout *mainLayout = new QVBoxLayout(this); - mainLayout->setContentsMargins(56, 40, 56, 40); - mainLayout->setSpacing(20); - - QLabel *subscribed = new QLabel(tr("✓ SUBSCRIBED")); - subscribed->setStyleSheet("font-size: 41px; font-weight: bold; color: #86FF4E;"); - mainLayout->addWidget(subscribed); - - QLabel *commaPrime = new QLabel(tr("comma prime")); - commaPrime->setStyleSheet("font-size: 75px; font-weight: bold;"); - mainLayout->addWidget(commaPrime); -} - - -PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(80, 90, 80, 60); - main_layout->setSpacing(0); - - QLabel *upgrade = new QLabel(tr("Upgrade Now")); - upgrade->setStyleSheet("font-size: 75px; font-weight: bold;"); - main_layout->addWidget(upgrade, 0, Qt::AlignTop); - main_layout->addSpacing(50); - - QLabel *description = new QLabel(tr("Become a comma prime member at connect.comma.ai")); - description->setStyleSheet("font-size: 56px; font-weight: light; color: white;"); - description->setWordWrap(true); - main_layout->addWidget(description, 0, Qt::AlignTop); - - main_layout->addStretch(); - - QLabel *features = new QLabel(tr("PRIME FEATURES:")); - features->setStyleSheet("font-size: 41px; font-weight: bold; color: #E5E5E5;"); - main_layout->addWidget(features, 0, Qt::AlignBottom); - main_layout->addSpacing(30); - - QVector bullets = {tr("Remote access"), tr("24/7 LTE connectivity"), tr("1 year of drive storage"), tr("Remote snapshots")}; - for (auto &b : bullets) { - const QString check = " "; - QLabel *l = new QLabel(check + b); - l->setAlignment(Qt::AlignLeft); - l->setStyleSheet("font-size: 50px; margin-bottom: 15px;"); - main_layout->addWidget(l, 0, Qt::AlignBottom); - } - - setStyleSheet(R"( - PrimeAdWidget { - border-radius: 10px; - background-color: #333333; - } - )"); -} - - -SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { - mainLayout = new QStackedWidget; - - // Unpaired, registration prompt layout - - QFrame* finishRegistration = new QFrame; - finishRegistration->setObjectName("primeWidget"); - QVBoxLayout* finishRegistrationLayout = new QVBoxLayout(finishRegistration); - finishRegistrationLayout->setSpacing(38); - finishRegistrationLayout->setContentsMargins(64, 48, 64, 48); - - QLabel* registrationTitle = new QLabel(tr("Finish Setup")); - registrationTitle->setStyleSheet("font-size: 75px; font-weight: bold;"); - finishRegistrationLayout->addWidget(registrationTitle); - - QLabel* registrationDescription = new QLabel(tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.")); - registrationDescription->setWordWrap(true); - registrationDescription->setStyleSheet("font-size: 50px; font-weight: light;"); - finishRegistrationLayout->addWidget(registrationDescription); - - finishRegistrationLayout->addStretch(); - - QPushButton* pair = new QPushButton(tr("Pair device")); - pair->setStyleSheet(R"( - QPushButton { - font-size: 55px; - font-weight: 500; - border-radius: 10px; - background-color: #465BEA; - padding: 64px; - } - QPushButton:pressed { - background-color: #3049F4; - } - )"); - finishRegistrationLayout->addWidget(pair); - - popup = new PairingPopup(this); - QObject::connect(pair, &QPushButton::clicked, popup, &PairingPopup::exec); - - mainLayout->addWidget(finishRegistration); - - // build stacked layout - QVBoxLayout *outer_layout = new QVBoxLayout(this); - outer_layout->setContentsMargins(0, 0, 0, 0); - outer_layout->addWidget(mainLayout); - - QWidget *content = new QWidget; - QVBoxLayout *content_layout = new QVBoxLayout(content); - content_layout->setContentsMargins(0, 0, 0, 0); - content_layout->setSpacing(30); - - WiFiPromptWidget *wifi_prompt = new WiFiPromptWidget; - QObject::connect(wifi_prompt, &WiFiPromptWidget::openSettings, this, &SetupWidget::openSettings); - content_layout->addWidget(wifi_prompt); - content_layout->addStretch(); - - mainLayout->addWidget(content); - - mainLayout->setCurrentIndex(1); - - setStyleSheet(R"( - #primeWidget { - border-radius: 10px; - background-color: #333333; - } - )"); - - // Retain size while hidden - QSizePolicy sp_retain = sizePolicy(); - sp_retain.setRetainSizeWhenHidden(true); - setSizePolicy(sp_retain); - - QObject::connect(uiState()->prime_state, &PrimeState::changed, [this](PrimeState::Type type) { - if (type == PrimeState::PRIME_TYPE_UNPAIRED) { - mainLayout->setCurrentIndex(0); // Display "Pair your device" widget - } else { - popup->reject(); - mainLayout->setCurrentIndex(1); // Display Wi-Fi prompt widget - } - }); -} diff --git a/selfdrive/ui/qt/widgets/prime.h b/selfdrive/ui/qt/widgets/prime.h deleted file mode 100644 index 266a90a92c..0000000000 --- a/selfdrive/ui/qt/widgets/prime.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "selfdrive/ui/qt/widgets/input.h" - -// pairing QR code -class PairingQRWidget : public QWidget { - Q_OBJECT - -public: - explicit PairingQRWidget(QWidget* parent = 0); - void paintEvent(QPaintEvent*) override; - -private: - QPixmap img; - QTimer *timer; - void updateQrCode(const QString &text); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - -private slots: - void refresh(); -}; - - -// pairing popup widget -class PairingPopup : public DialogBase { - Q_OBJECT - -public: - explicit PairingPopup(QWidget* parent); - int exec() override; -}; - - -// widget for paired users with prime -class PrimeUserWidget : public QFrame { - Q_OBJECT - -public: - explicit PrimeUserWidget(QWidget* parent = 0); -}; - - -// widget for paired users without prime -class PrimeAdWidget : public QFrame { - Q_OBJECT -public: - explicit PrimeAdWidget(QWidget* parent = 0); -}; - - -// container widget -class SetupWidget : public QFrame { - Q_OBJECT - -public: - explicit SetupWidget(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString ¶m = ""); - -private: - PairingPopup *popup; - QStackedWidget *mainLayout; -}; diff --git a/selfdrive/ui/qt/widgets/scrollview.cc b/selfdrive/ui/qt/widgets/scrollview.cc deleted file mode 100644 index 978bf83a63..0000000000 --- a/selfdrive/ui/qt/widgets/scrollview.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include "selfdrive/ui/qt/widgets/scrollview.h" - -#include -#include - -// TODO: disable horizontal scrolling and resize - -ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent) { - setWidget(w); - setWidgetResizable(true); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setStyleSheet("background-color: transparent; border:none"); - - QString style = R"( - QScrollBar:vertical { - border: none; - background: transparent; - width: 10px; - margin: 0; - } - QScrollBar::handle:vertical { - min-height: 0px; - border-radius: 5px; - background-color: white; - } - QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { - height: 0px; - } - QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background: none; - } - )"; - verticalScrollBar()->setStyleSheet(style); - horizontalScrollBar()->setStyleSheet(style); - - QScroller *scroller = QScroller::scroller(this->viewport()); - QScrollerProperties sp = scroller->scrollerProperties(); - - sp.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); - sp.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); - sp.setScrollMetric(QScrollerProperties::MousePressEventDelay, 0.01); - scroller->grabGesture(this->viewport(), QScroller::LeftMouseButtonGesture); - scroller->setScrollerProperties(sp); -} - -void ScrollView::hideEvent(QHideEvent *e) { - verticalScrollBar()->setValue(0); -} diff --git a/selfdrive/ui/qt/widgets/scrollview.h b/selfdrive/ui/qt/widgets/scrollview.h deleted file mode 100644 index 024331aa39..0000000000 --- a/selfdrive/ui/qt/widgets/scrollview.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -class ScrollView : public QScrollArea { - Q_OBJECT - -public: - explicit ScrollView(QWidget *w = nullptr, QWidget *parent = nullptr); -protected: - void hideEvent(QHideEvent *e) override; -}; diff --git a/selfdrive/ui/qt/widgets/ssh_keys.cc b/selfdrive/ui/qt/widgets/ssh_keys.cc deleted file mode 100644 index 26743952de..0000000000 --- a/selfdrive/ui/qt/widgets/ssh_keys.cc +++ /dev/null @@ -1,64 +0,0 @@ -#include "selfdrive/ui/qt/widgets/ssh_keys.h" - -#include "common/params.h" -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/qt/widgets/input.h" - -SshControl::SshControl() : - ButtonControl(tr("SSH Keys"), "", tr("Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username " - "other than your own. A comma employee will NEVER ask you to add their GitHub username.")) { - - QObject::connect(this, &ButtonControl::clicked, [=]() { - if (text() == tr("ADD")) { - QString username = InputDialog::getText(tr("Enter your GitHub username"), this); - if (username.length() > 0) { - setText(tr("LOADING")); - setEnabled(false); - getUserKeys(username); - } - } else { - params.remove("GithubUsername"); - params.remove("GithubSshKeys"); - refresh(); - } - }); - - refresh(); -} - -void SshControl::refresh() { - QString param = QString::fromStdString(params.get("GithubSshKeys")); - if (param.length()) { - setValue(QString::fromStdString(params.get("GithubUsername"))); - setText(tr("REMOVE")); - } else { - setValue(""); - setText(tr("ADD")); - } - setEnabled(true); -} - -void SshControl::getUserKeys(const QString &username) { - HttpRequest *request = new HttpRequest(this, false); - QObject::connect(request, &HttpRequest::requestDone, [=](const QString &resp, bool success) { - if (success) { - if (!resp.isEmpty()) { - params.put("GithubUsername", username.toStdString()); - params.put("GithubSshKeys", resp.toStdString()); - } else { - ConfirmationDialog::alert(tr("Username '%1' has no keys on GitHub").arg(username), this); - } - } else { - if (request->timeout()) { - ConfirmationDialog::alert(tr("Request timed out"), this); - } else { - ConfirmationDialog::alert(tr("Username '%1' doesn't exist on GitHub").arg(username), this); - } - } - - refresh(); - request->deleteLater(); - }); - - request->sendRequest("https://github.com/" + username + ".keys"); -} diff --git a/selfdrive/ui/qt/widgets/ssh_keys.h b/selfdrive/ui/qt/widgets/ssh_keys.h deleted file mode 100644 index 920bd651e2..0000000000 --- a/selfdrive/ui/qt/widgets/ssh_keys.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/widgets/controls.h" - -// SSH enable toggle -class SshToggle : public ToggleControl { - Q_OBJECT - -public: - SshToggle() : ToggleControl(tr("Enable SSH"), "", "", Hardware::get_ssh_enabled()) { - QObject::connect(this, &SshToggle::toggleFlipped, [=](bool state) { - Hardware::set_ssh_enabled(state); - }); - } -}; - -// SSH key management widget -class SshControl : public ButtonControl { - Q_OBJECT - -public: - SshControl(); - -private: - Params params; - - void refresh(); - void getUserKeys(const QString &username); -}; diff --git a/selfdrive/ui/qt/widgets/toggle.cc b/selfdrive/ui/qt/widgets/toggle.cc deleted file mode 100644 index 82302ad5bc..0000000000 --- a/selfdrive/ui/qt/widgets/toggle.cc +++ /dev/null @@ -1,83 +0,0 @@ -#include "selfdrive/ui/qt/widgets/toggle.h" - -#include - -Toggle::Toggle(QWidget *parent) : QAbstractButton(parent), -_height(80), -_height_rect(60), -on(false), -_anim(new QPropertyAnimation(this, "offset_circle", this)) -{ - _radius = _height / 2; - _x_circle = _radius; - _y_circle = _radius; - _y_rect = (_height - _height_rect)/2; - circleColor = QColor(0xffffff); // placeholder - green = QColor(0xffffff); // placeholder - setEnabled(true); -} - -void Toggle::paintEvent(QPaintEvent *e) { - this->setFixedHeight(_height); - QPainter p(this); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing, true); - - // Draw toggle background left - p.setBrush(green); - p.drawRoundedRect(QRect(0, _y_rect, _x_circle + _radius, _height_rect), _height_rect/2, _height_rect/2); - - // Draw toggle background right - p.setBrush(QColor(0x393939)); - p.drawRoundedRect(QRect(_x_circle - _radius, _y_rect, width() - (_x_circle - _radius), _height_rect), _height_rect/2, _height_rect/2); - - // Draw toggle circle - p.setBrush(circleColor); - p.drawEllipse(QRectF(_x_circle - _radius, _y_circle - _radius, 2 * _radius, 2 * _radius)); -} - -void Toggle::mouseReleaseEvent(QMouseEvent *e) { - if (!enabled) { - return; - } - const int left = _radius; - const int right = width() - _radius; - if ((_x_circle != left && _x_circle != right) || !this->rect().contains(e->localPos().toPoint())) { - // If mouse release isn't in rect or animation is running, don't parse touch events - return; - } - if (e->button() & Qt::LeftButton) { - togglePosition(); - emit stateChanged(on); - } -} - -void Toggle::togglePosition() { - on = !on; - const int left = _radius; - const int right = width() - _radius; - _anim->setStartValue(on ? left + immediateOffset : right - immediateOffset); - _anim->setEndValue(on ? right : left); - _anim->setDuration(animation_duration); - _anim->start(); - repaint(); -} - -void Toggle::enterEvent(QEvent *e) { - QAbstractButton::enterEvent(e); -} - -bool Toggle::getEnabled() { - return enabled; -} - -void Toggle::setEnabled(bool value) { - enabled = value; - if (value) { - circleColor.setRgb(0xfafafa); - green.setRgb(0x33ab4c); - } else { - circleColor.setRgb(0x888888); - green.setRgb(0x227722); - } -} diff --git a/selfdrive/ui/qt/widgets/toggle.h b/selfdrive/ui/qt/widgets/toggle.h deleted file mode 100644 index e7263a008f..0000000000 --- a/selfdrive/ui/qt/widgets/toggle.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include - -class Toggle : public QAbstractButton { - Q_OBJECT - Q_PROPERTY(int offset_circle READ offset_circle WRITE set_offset_circle CONSTANT) - -public: - Toggle(QWidget* parent = nullptr); - void togglePosition(); - bool on; - int animation_duration = 150; - int immediateOffset = 0; - int offset_circle() const { - return _x_circle; - } - - void set_offset_circle(int o) { - _x_circle = o; - update(); - } - bool getEnabled(); - void setEnabled(bool value); - -protected: - void paintEvent(QPaintEvent*) override; - void mouseReleaseEvent(QMouseEvent*) override; - void enterEvent(QEvent*) override; - -private: - QColor circleColor; - QColor green; - bool enabled = true; - int _x_circle, _y_circle; - int _height, _radius; - int _height_rect, _y_rect; - QPropertyAnimation *_anim = nullptr; - -signals: - void stateChanged(bool new_state); -}; diff --git a/selfdrive/ui/qt/widgets/wifi.cc b/selfdrive/ui/qt/widgets/wifi.cc deleted file mode 100644 index d7eb8beeb3..0000000000 --- a/selfdrive/ui/qt/widgets/wifi.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "selfdrive/ui/qt/widgets/wifi.h" - -#include -#include -#include -#include - -WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { - // Setup Firehose Mode - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(56, 40, 56, 40); - main_layout->setSpacing(42); - - QLabel *title = new QLabel(tr("🔥 Firehose Mode 🔥")); - title->setStyleSheet("font-size: 64px; font-weight: 500;"); - main_layout->addWidget(title); - - QLabel *desc = new QLabel(tr("Maximize your training data uploads to improve openpilot's driving models.")); - desc->setStyleSheet("font-size: 40px; font-weight: 400;"); - desc->setWordWrap(true); - main_layout->addWidget(desc); - - QPushButton *settings_btn = new QPushButton(tr("Open")); - connect(settings_btn, &QPushButton::clicked, [=]() { emit openSettings(1, "FirehosePanel"); }); - settings_btn->setStyleSheet(R"( - QPushButton { - font-size: 48px; - font-weight: 500; - border-radius: 10px; - background-color: #465BEA; - padding: 32px; - } - QPushButton:pressed { - background-color: #3049F4; - } - )"); - main_layout->addWidget(settings_btn); - - setStyleSheet(R"( - WiFiPromptWidget { - background-color: #333333; - border-radius: 10px; - } - )"); -} \ No newline at end of file diff --git a/selfdrive/ui/qt/widgets/wifi.h b/selfdrive/ui/qt/widgets/wifi.h deleted file mode 100644 index 3e68a15b7b..0000000000 --- a/selfdrive/ui/qt/widgets/wifi.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -class WiFiPromptWidget : public QFrame { - Q_OBJECT - -public: - explicit WiFiPromptWidget(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString ¶m = ""); -}; diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc deleted file mode 100644 index 6b579fcc5d..0000000000 --- a/selfdrive/ui/qt/window.cc +++ /dev/null @@ -1,98 +0,0 @@ -#include "selfdrive/ui/qt/window.h" - -#include - -#include "system/hardware/hw.h" - -MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { - main_layout = new QStackedLayout(this); - main_layout->setMargin(0); - - homeWindow = new HomeWindow(this); - main_layout->addWidget(homeWindow); - QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings); - QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings); - - settingsWindow = new SettingsWindow(this); - main_layout->addWidget(settingsWindow); - QObject::connect(settingsWindow, &SettingsWindow::closeSettings, this, &MainWindow::closeSettings); - QObject::connect(settingsWindow, &SettingsWindow::reviewTrainingGuide, [=]() { - onboardingWindow->showTrainingGuide(); - main_layout->setCurrentWidget(onboardingWindow); - }); - QObject::connect(settingsWindow, &SettingsWindow::showDriverView, [=] { - homeWindow->showDriverView(true); - }); - - onboardingWindow = new OnboardingWindow(this); - main_layout->addWidget(onboardingWindow); - QObject::connect(onboardingWindow, &OnboardingWindow::onboardingDone, [=]() { - main_layout->setCurrentWidget(homeWindow); - }); - if (!onboardingWindow->completed()) { - main_layout->setCurrentWidget(onboardingWindow); - } - - QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - if (!offroad) { - closeSettings(); - } - }); - QObject::connect(device(), &Device::interactiveTimeout, [=]() { - if (main_layout->currentWidget() == settingsWindow) { - closeSettings(); - } - }); - - // load fonts - QFontDatabase::addApplicationFont("../assets/fonts/Inter-Black.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-Bold.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-ExtraBold.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-ExtraLight.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-Medium.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-Regular.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-SemiBold.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/Inter-Thin.ttf"); - QFontDatabase::addApplicationFont("../assets/fonts/JetBrainsMono-Medium.ttf"); - - // no outline to prevent the focus rectangle - setStyleSheet(R"( - * { - font-family: Inter; - outline: none; - } - )"); - setAttribute(Qt::WA_NoSystemBackground); -} - -void MainWindow::openSettings(int index, const QString ¶m) { - main_layout->setCurrentWidget(settingsWindow); - settingsWindow->setCurrentPanel(index, param); -} - -void MainWindow::closeSettings() { - main_layout->setCurrentWidget(homeWindow); - - if (uiState()->scene.started) { - homeWindow->showSidebar(false); - } -} - -bool MainWindow::eventFilter(QObject *obj, QEvent *event) { - bool ignore = false; - switch (event->type()) { - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::MouseButtonPress: - case QEvent::MouseMove: { - // ignore events when device is awakened by resetInteractiveTimeout - ignore = !device()->isAwake(); - device()->resetInteractiveTimeout(); - break; - } - default: - break; - } - return ignore; -} diff --git a/selfdrive/ui/qt/window.h b/selfdrive/ui/qt/window.h deleted file mode 100644 index 05b61e1f76..0000000000 --- a/selfdrive/ui/qt/window.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -#include "selfdrive/ui/qt/home.h" -#include "selfdrive/ui/qt/offroad/onboarding.h" -#include "selfdrive/ui/qt/offroad/settings.h" - -class MainWindow : public QWidget { - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - -private: - bool eventFilter(QObject *obj, QEvent *event) override; - void openSettings(int index = 0, const QString ¶m = ""); - void closeSettings(); - - QStackedLayout *main_layout; - HomeWindow *homeWindow; - SettingsWindow *settingsWindow; - OnboardingWindow *onboardingWindow; -}; diff --git a/selfdrive/ui/tests/create_test_translations.sh b/selfdrive/ui/tests/create_test_translations.sh deleted file mode 100755 index 1587a88205..0000000000 --- a/selfdrive/ui/tests/create_test_translations.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -e - -UI_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"/.. -TEST_TEXT="(WRAPPED_SOURCE_TEXT)" -TEST_TS_FILE=$UI_DIR/translations/test_en.ts -TEST_QM_FILE=$UI_DIR/translations/test_en.qm - -# translation strings -UNFINISHED="<\/translation>" -TRANSLATED="$TEST_TEXT<\/translation>" - -mkdir -p $UI_DIR/translations -rm -f $TEST_TS_FILE $TEST_QM_FILE -lupdate -recursive "$UI_DIR" -ts $TEST_TS_FILE -sed -i "s/$UNFINISHED/$TRANSLATED/" $TEST_TS_FILE -lrelease $TEST_TS_FILE diff --git a/selfdrive/ui/tests/test_runner.cc b/selfdrive/ui/tests/test_runner.cc deleted file mode 100644 index 4bde921696..0000000000 --- a/selfdrive/ui/tests/test_runner.cc +++ /dev/null @@ -1,26 +0,0 @@ -#define CATCH_CONFIG_RUNNER -#include "catch2/catch.hpp" - -#include -#include -#include -#include - -int main(int argc, char **argv) { - // unit tests for Qt - QApplication app(argc, argv); - - QString language_file = "test_en"; - // FIXME: pytest-cpp considers this print as a test case - qDebug() << "Loading language:" << language_file; - - QTranslator translator; - QString translationsPath = QDir::cleanPath(qApp->applicationDirPath() + "/../translations"); - if (!translator.load(language_file, translationsPath)) { - qDebug() << "Failed to load translation file!"; - } - app.installTranslator(&translator); - - const int res = Catch::Session().run(argc, argv); - return (res < 0xff ? res : 0xff); -} diff --git a/selfdrive/ui/tests/test_translations.cc b/selfdrive/ui/tests/test_translations.cc deleted file mode 100644 index fcefc5784f..0000000000 --- a/selfdrive/ui/tests/test_translations.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "catch2/catch.hpp" - -#include "common/params.h" -#include "selfdrive/ui/qt/window.h" - -const QString TEST_TEXT = "(WRAPPED_SOURCE_TEXT)"; // what each string should be translated to -QRegExp RE_NUM("\\d*"); - -QStringList getParentWidgets(QWidget* widget){ - QStringList parentWidgets; - while (widget->parentWidget() != Q_NULLPTR) { - widget = widget->parentWidget(); - parentWidgets.append(widget->metaObject()->className()); - } - return parentWidgets; -} - -template -void checkWidgetTrWrap(MainWindow &w) { - for (auto widget : w.findChildren()) { - const QString text = widget->text(); - bool isNumber = RE_NUM.exactMatch(text); - bool wrapped = text.contains(TEST_TEXT); - QString parentWidgets = getParentWidgets(widget).join("->"); - - if (!text.isEmpty() && !isNumber && !wrapped) { - FAIL(("\"" + text + "\" must be wrapped. Parent widgets: " + parentWidgets).toStdString()); - } - - // warn if source string wrapped, but UI adds text - // TODO: add way to ignore this - if (wrapped && text != TEST_TEXT) { - WARN(("\"" + text + "\" is dynamic and needs a custom retranslate function. Parent widgets: " + parentWidgets).toStdString()); - } - } -} - -// Tests all strings in the UI are wrapped with tr() -TEST_CASE("UI: test all strings wrapped") { - Params().remove("LanguageSetting"); - Params().remove("HardwareSerial"); - Params().remove("DongleId"); - qputenv("TICI", "1"); - - MainWindow w; - checkWidgetTrWrap(w); - checkWidgetTrWrap(w); -} diff --git a/selfdrive/ui/tests/test_translations.py b/selfdrive/ui/tests/test_translations.py index edd9a30412..5308a44ea5 100644 --- a/selfdrive/ui/tests/test_translations.py +++ b/selfdrive/ui/tests/test_translations.py @@ -6,8 +6,7 @@ import xml.etree.ElementTree as ET import string import requests from parameterized import parameterized_class - -from openpilot.selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE +from openpilot.system.ui.lib.multilang import TRANSLATIONS_DIR, LANGUAGES_FILE with open(LANGUAGES_FILE) as f: translation_files = json.load(f) @@ -17,6 +16,7 @@ LOCATION_TAG = " - - - - AbstractAlert - - Close - إغلاق - - - Reboot and Update - إعادة التشغيل والتحديث - - - - AdvancedNetworking - - Back - السابق - - - Enable Tethering - تمكين الربط - - - Tethering Password - كلمة مرور الربط - - - EDIT - تعديل - - - Enter new tethering password - أدخل كلمة مرور الربط الجديدة - - - IP Address - عنوان IP - - - Enable Roaming - تمكين التجوال - - - APN Setting - إعدادات APN - - - Enter APN - إدخال APN - - - leave blank for automatic configuration - اتركه فارغاً من أجل التكوين التلقائي - - - Cellular Metered - محدود بالاتصال الخلوي - - - Hidden Network - شبكة مخفية - - - CONNECT - الاتصال - - - Enter SSID - أدخل SSID - - - Enter password - أدخل كلمة المرور - - - for "%1" - من أجل "%1" - - - Prevent large data uploads when on a metered cellular connection - - - - default - - - - metered - - - - unmetered - - - - Wi-Fi Network Metered - - - - Prevent large data uploads when on a metered Wi-Fi connection - - - - - ConfirmationDialog - - Ok - موافق - - - Cancel - إلغاء - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - يجب عليك قبول الشروط والأحكام من أجل استخدام openpilot. - - - Back - السابق - - - Decline, uninstall %1 - رفض، إلغاء التثبيت %1 - - - - DeveloperPanel - - Joystick Debug Mode - وضع تصحيح أخطاء عصا التحكم - - - Longitudinal Maneuver Mode - وضع المناورة الطولية - - - openpilot Longitudinal Control (Alpha) - التحكم الطولي openpilot (ألفا) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - تحذير: التحكم الطولي في openpilot في المرحلة ألفا لهذه السيارة، وسيقوم بتعطيل مكابح الطوارئ الآلية (AEB). - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - في هذه السيارة يعمل openpilot افتراضياً بالشكل المدمج في التحكم التكيفي في السرعة بدلاً من التحكم الطولي. قم بتمكين هذا الخيار من أجل الانتقال إلى التحكم الطولي. يوصى بتمكين الوضع التجريبي عند استخدام وضع التحكم الطولي ألفا من openpilot. - - - Enable ADB - تمكين ADB - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - أداة ADB (Android Debug Bridge) تسمح بالاتصال بجهازك عبر USB أو عبر الشبكة. راجع هذا الرابط: https://docs.comma.ai/how-to/connect-to-comma لمزيد من المعلومات. - - - - DevicePanel - - Dongle ID - معرف دونجل - - - N/A - غير متاح - - - Serial - الرقم التسلسلي - - - Driver Camera - كاميرة السائق - - - PREVIEW - معاينة - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - قم بمعاينة الكاميرا المواجهة للسائق للتأكد من أن نظام مراقبة السائق يتمتع برؤية جيدة. (يجب أن تكون السيارة متوقفة) - - - Reset Calibration - إعادة ضبط المعايرة - - - RESET - إعادة الضبط - - - Are you sure you want to reset calibration? - هل أنت متأكد أنك تريد إعادة ضبط المعايرة؟ - - - Review Training Guide - مراجعة دليل التدريب - - - REVIEW - مراجعة - - - Review the rules, features, and limitations of openpilot - مراجعة الأدوار والميزات والقيود في openpilot - - - Are you sure you want to review the training guide? - هل أنت متأكد أنك تريد مراجعة دليل التدريب؟ - - - Regulatory - التنظيمية - - - VIEW - عرض - - - Change Language - تغيير اللغة - - - CHANGE - تغيير - - - Select a language - اختر لغة - - - Reboot - إعادة التشغيل - - - Power Off - إيقاف التشغيل - - - Your device is pointed %1° %2 and %3° %4. - يشير جهازك إلى %1 درجة %2، و%3 درجة %4. - - - down - نحو الأسفل - - - up - نحو الأعلى - - - left - نحو اليسار - - - right - نحو اليمين - - - Are you sure you want to reboot? - هل أنت متأكد أنك تريد إعادة التشغيل؟ - - - Disengage to Reboot - فك الارتباط من أجل إعادة التشغيل - - - Are you sure you want to power off? - هل أنت متأكد أنك تريد إيقاف التشغيل؟ - - - Disengage to Power Off - فك الارتباط من أجل إيقاف التشغيل - - - Reset - إعادة الضبط - - - Review - مراجعة - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - اقرن جهازك بجهاز (connect.comma.ai) واحصل على عرضك من comma prime. - - - Pair Device - إقران الجهاز - - - PAIR - إقران - - - Disengage to Reset Calibration - - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - -Steering lag calibration is %1% complete. - - - - - -Steering lag calibration is complete. - - - - Steering torque response calibration is %1% complete. - - - - Steering torque response calibration is complete. - - - - - DriverViewWindow - - camera starting - بدء تشغيل الكاميرا - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - تشغيل الوضع التجريبي - - - CHILL MODE ON - تشغيل وضع الراحة - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - يتعلم تطبيق openpilot كيفية القيادة من خلال مشاهدة البشر، مثلك، أثناء القيادة. - -يتيح لك وضع خرطوم الحريق زيادة تحميلات بيانات التدريب لتحسين نماذج القيادة في OpenPilot. كلما زادت البيانات، زادت النماذج، مما يعني وضعًا تجريبيًا أفضل. - - - Firehose Mode: ACTIVE - وضع خرطوم الحريق: نشط - - - ACTIVE - نشط - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - للحصول على أقصى فعالية، أحضر جهازك إلى الداخل واتصل بمحول USB-C جيد وشبكة Wi-Fi أسبوعياً.<br><br>يمكن أن يعمل وضع خرطوم الحريق أيضاً أثناء القيادة إذا كنت متصلاً بنقطة اتصال أو ببطاقة SIM غير محدودة.<br><br><br><b>الأسئلة المتكررة</b><br><br><i>هل يهم كيف أو أين أقود؟</i> لا، فقط قد كما تفعل عادة.<br><br><i>هل يتم سحب كل مقاطع رحلاتي في وضع خرطوم الحريق؟</i> لا، نقوم بسحب مجموعة مختارة من مقاطع رحلاتك.<br><br><i>ما هو محول USB-C الجيد؟</i> أي شاحن سريع للهاتف أو اللابتوب يجب أن يكون مناسباً.<br><br><i>هل يهم أي برنامج أستخدم؟</i> نعم، فقط النسخة الأصلية من openpilot (وأفرع معينة) يمكن استخدامها للتدريب. - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - - - - Firehose Mode - - - - - HudRenderer - - km/h - كم/س - - - mph - ميل/س - - - MAX - MAX - - - - InputDialog - - Cancel - إلغاء - - - Need at least %n character(s)! - - تحتاج إلى حرف %n على الأقل! - تحتاج إلى حرف %n على الأقل! - تحتاج إلى حرفين %n على الأقل! - تحتاج إلى %n أحرف على الأقل! - تحتاج إلى %n أحرف على الأقل! - تحتاج إلى %n حرف على الأقل! - - - - - MultiOptionDialog - - Select - اختيار - - - Cancel - إلغاء - - - - Networking - - Advanced - متقدم - - - Enter password - أدخل كلمة المرور - - - for "%1" - من أجل "%1" - - - Wrong password - كلمة مرور خاطئة - - - - OffroadAlert - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - درجة حرارة الجهاز مرتفعة جداً. يقوم النظام بالتبريد قبل البدء. درجة الحرارة الحالية للمكونات الداخلية: %1 - - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - اتصل فوراً بالإنترنت للتحقق من وجود تحديثات. إذا لم تكم متصلاً بالإنترنت فإن openpilot لن يساهم في %1 - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - اتصل بالإنترنت للتحقق من وجود تحديثات. لا يعمل openpilot تلقائياً إلا إذا اتصل بالإنترنت من أجل التحقق من التحديثات. - - - Unable to download updates -%1 - غير قادر على تحميل التحديثات -%1 - - - Taking camera snapshots. System won't start until finished. - التقاط لقطات كاميرا. لن يبدأ النظام حتى تنتهي هذه العملية. - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - يتم تنزيل تحديث لنظام تشغيل جهازك في الخلفية. سيطلَب منك التحديث عندما يصبح جاهزاً للتثبيت. - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - لم يكن openpilot قادراً على تحديد سيارتك. إما أن تكون سيارتك غير مدعومة أو أنه لم يتم التعرف على وحدة التحكم الإلكتروني (ECUs) فيها. يرجى تقديم طلب سحب من أجل إضافة نسخ برمجيات ثابتة إلى السيارة المناسبة. هل تحتاج إلى أي مساعدة؟ لا تتردد في التواصل مع doscord.comma.ai. - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - لقد اكتشف openpilot تغييراً في موقع تركيب الجهاز. تأكد من تثبيت الجهاز بشكل كامل في موقعه وتثبيته بإحكام على الزجاج الأمامي. - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - - - - Acknowledge Excessive Actuation - - - - Snooze Update - تأخير التحديث - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - تحديث - - - ALERTS - التنبهات - - - ALERT - تنبيه - - - - OnroadAlerts - - openpilot Unavailable - openpilot غير متوفر - - - TAKE CONTROL IMMEDIATELY - تحكم على الفور - - - Reboot Device - إعادة التشغيل - - - Waiting to start - في انتظار البدء - - - System Unresponsive - النظام لا يستجيب - - - - PairingPopup - - Pair your device to your comma account - اقرن جهازك مع حسابك على comma - - - Go to https://connect.comma.ai on your phone - انتقل إلى https://connect.comma.ai على جوالك - - - Click "add new device" and scan the QR code on the right - انقر "،إضافة جهاز جديد"، وامسح رمز الاستجابة السريعة (QR) على اليمين - - - Bookmark connect.comma.ai to your home screen to use it like an app - اجعل لـconnect.comma.ai إشارة مرجعية على شاشتك الرئيسية من أجل استخدامه مثل أي تطبيق - - - Please connect to Wi-Fi to complete initial pairing - يرجى الاتصال بشبكة الواي فاي لإكمال الاقتران الأولي - - - - ParamControl - - Enable - تمكين - - - Cancel - إلغاء - - - - PrimeAdWidget - - Upgrade Now - الترقية الآن - - - Become a comma prime member at connect.comma.ai - كن عضوًا في comma prime على connect.comma.ai - - - PRIME FEATURES: - الميزات الأساسية: - - - Remote access - التحكم عن بعد - - - 24/7 LTE connectivity - اتصال LTE على مدار الساعة 24/7 - - - 1 year of drive storage - سنة واحدة من تخزين القرص - - - Remote snapshots - لقطات عن بُعد - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ مشترك - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - منذ %n دقيقة - منذ %n دقيقة - منذ دقيقتين %n - منذ %n دقائق - منذ %n دقائق - منذ %n دقيقة - - - - %n hour(s) ago - - منذ %n ساعة - منذ %n ساعة - منذ ساعتين %n - منذ %n ساعات - منذ %n ساعات - منذ %n ساعة - - - - %n day(s) ago - - منذ %n يوم - منذ %n يوم - منذ يومين %n - منذ %n أيام - منذ %n أيام - منذ %n يوم - - - - now - الآن - - - - SettingsWindow - - × - × - - - Device - الجهاز - - - Network - الشبكة - - - Toggles - المثبتتات - - - Software - البرنامج - - - Developer - المطور - - - Firehose - خرطوم الحريق - - - - SetupWidget - - Finish Setup - إنهاء الإعداد - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - اقرن جهازك بجهاز (connect.comma.ai) واحصل على عرضك من comma prime. - - - Pair device - اقتران الجهاز - - - - Sidebar - - CONNECT - الاتصال - - - OFFLINE - غير متصل - - - ONLINE - متصل - - - ERROR - خطأ - - - TEMP - درجة الحرارة - - - HIGH - مرتفع - - - GOOD - جيد - - - OK - موافق - - - VEHICLE - المركبة - - - NO - لا - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - UNINSTALL - إلغاء التثبيت - - - Uninstall %1 - إلغاء التثبيت %1 - - - Are you sure you want to uninstall? - هل أنت متأكد أنك تريد إلغاء التثبيت؟ - - - CHECK - التحقق - - - Updates are only downloaded while the car is off. - يتم تحميل التحديثات فقط عندما تكون السيارة متوقفة. - - - Current Version - النسخة الحالية - - - Download - تنزيل - - - Install Update - تثبيت التحديث - - - INSTALL - تثبيت - - - Target Branch - فرع الهدف - - - SELECT - اختيار - - - Select a branch - اختر فرعاً - - - Uninstall - إلغاء التثبيت - - - failed to check for update - فشل التحقق من التحديث - - - DOWNLOAD - تنزيل - - - update available - يتوفر تحديث - - - never - إطلاقاً - - - up to date, last checked %1 - أحدث نسخة، آخر تحقق %1 - - - - SshControl - - SSH Keys - مفاتيح SSH - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - تنبيه: هذا يمنح SSH إمكانية الوصول إلى جميع المفاتيح العامة في إعدادات GitHub. لا تقم بإدخال اسم مستخدم GitHub بدلاً من اسمك. لن تطلب منك comma employee إطلاقاً أن تضيف اسم مستخدم GitHub الخاص بهم. - - - ADD - إضافة - - - Enter your GitHub username - ادخل اسم المستخدم GitHub الخاص بك - - - LOADING - يتم التحميل - - - REMOVE - إزالة - - - Username '%1' has no keys on GitHub - لا يحتوي اسم المستخدم '%1' أي مفاتيح على GitHub - - - Request timed out - انتهى وقت الطلب - - - Username '%1' doesn't exist on GitHub - اسم المستخدم '%1' غير موجود على GitHub - - - - SshToggle - - Enable SSH - تمكين SSH - - - - TermsPage - - Decline - رفض - - - Agree - أوافق - - - Welcome to openpilot - مرحباً بكم في openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - يجب عليك قبول الشروط والأحكام لاستخدام openpilot. اقرأ أحدث الشروط على <span style='color: #465BEA;'>https://comma.ai/terms</span> قبل الاستمرار. - - - - TogglesPanel - - Enable openpilot - تمكين openpilot - - - Enable Lane Departure Warnings - قم بتمكين تحذيرات مغادرة المسار - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - تلقي التنبيهات من أجل الالتفاف للعودة إلى المسار عندما تنحرف سيارتك فوق الخط المحدد للمسار دون تشغيل إشارة الانعطاف عند القيادة لمسافة تزيد عن 31 ميل/سا (50 كم/سا). - - - Use Metric System - استخدام النظام المتري - - - Display speed in km/h instead of mph. - عرض السرعة بواحدات كم/سا بدلاً من ميل/سا. - - - Record and Upload Driver Camera - تسجيل وتحميل كاميرا السائق - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - تحميل البيانات من الكاميرا المواجهة للسائق، والمساعدة في تحسين خوارزمية مراقبة السائق. - - - Disengage on Accelerator Pedal - فك الارتباط عن دواسة الوقود - - - When enabled, pressing the accelerator pedal will disengage openpilot. - عند تمكين هذه الميزة، فإن الضغط على دواسة الوقود سيؤدي إلى فك ارتباط openpilot. - - - Experimental Mode - الوضع التجريبي - - - Aggressive - الهجومي - - - Standard - القياسي - - - Relaxed - الراحة - - - Driving Personality - شخصية القيادة - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - يتم وضع openpilot بشكل قياسي في <b>وضعية الراحة</b>. يمكن الوضع التجريبي <b>ميزات المستوى ألفا</b> التي لا تكون جاهزة في وضع الراحة: - - - End-to-End Longitudinal Control - التحكم الطولي من طرف إلى طرف - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - دع نظام القيادة يتحكم بالوقود والمكابح. سيقوم openpilot بالقيادة كما لو أنه كائن بشري، بما في ذلك التوقف عند الإشارة الحمراء، وإشارات التوقف. وبما أن نمط القيادة يحدد سرعة القيادة، فإن السرعة المضبوطة تشكل الحد الأقصى فقط. هذه خاصية الجودة ألفا، فيجب توقع حدوث الأخطاء. - - - New Driving Visualization - تصور القيادة الديد - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - الوضع التجريبي غير متوفر حالياً في هذه السيارة نظراً لاستخدام رصيد التحكم التكيفي بالسرعة من أجل التحكم الطولي. - - - openpilot longitudinal control may come in a future update. - قد يتم الحصول على التحكم الطولي في openpilot في عمليات التحديث المستقبلية. - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - يمكن اختبار نسخة ألفا من التحكم الطولي من openpilot، مع الوضع التجريبي، لكن على الفروع غير المطلقة. - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - تمكين التحكم الطولي من openpilot (ألفا) للسماح بالوضع التجريبي. - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - يوصى بالمعيار. في الوضع العدواني، سيتبع الطيار المفتوح السيارات الرائدة بشكل أقرب ويكون أكثر عدوانية مع البنزين والفرامل. في الوضع المريح، سيبقى openpilot بعيدًا عن السيارات الرائدة. في السيارات المدعومة، يمكنك التنقل بين هذه الشخصيات باستخدام زر مسافة عجلة القيادة. - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - ستتحول واجهة القيادة إلى الكاميرا الواسعة المواجهة للطريق عند السرعات المنخفضة لعرض بعض المنعطفات بشكل أفضل. كما سيتم عرض شعار وضع التجريبي في الزاوية العلوية اليمنى. - - - Always-On Driver Monitoring - مراقبة السائق المستمرة - - - Enable driver monitoring even when openpilot is not engaged. - تمكين مراقبة السائق حتى عندما لا يكون نظام OpenPilot مُفعّلاً. - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Record and Upload Microphone Audio - - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - WiFiPromptWidget - - Open - انفتح - - - Maximize your training data uploads to improve openpilot's driving models. - قم بزيادة تحميلات بيانات التدريب الخاصة بك لتحسين نماذج القيادة الخاصة بـ openpilot. - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> وضع خرطوم الحريق <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - يتم البحث عن شبكات... - - - CONNECTING... - يتم الاتصال... - - - FORGET - نسيان هذه الشبكة - - - Forget Wi-Fi Network "%1"? - هل تريد نسيان شبكة الواي فاي "%1"؟ - - - Forget - نسيان - - - diff --git a/selfdrive/ui/translations/create_badges.py b/selfdrive/ui/translations/create_badges.py deleted file mode 100755 index 3e14c33255..0000000000 --- a/selfdrive/ui/translations/create_badges.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -import json -import os -import requests -import xml.etree.ElementTree as ET - -from openpilot.common.basedir import BASEDIR -from openpilot.selfdrive.ui.tests.test_translations import UNFINISHED_TRANSLATION_TAG -from openpilot.selfdrive.ui.update_translations import LANGUAGES_FILE, TRANSLATIONS_DIR - -TRANSLATION_TAG = " 90 else (204, 55, 27)}" - - # Download badge - badge_label = f"LANGUAGE {name}" - badge_message = f"{percent_finished}% complete" - if unfinished_translations != 0: - badge_message += f" ({unfinished_translations} unfinished)" - - r = requests.get(f"{SHIELDS_URL}/{badge_label}-{badge_message}-{color}", timeout=10) - assert r.status_code == 200, "Error downloading badge" - content_svg = r.content.decode("utf-8") - - xml = ET.fromstring(content_svg) - assert "width" in xml.attrib - max_badge_width = max(max_badge_width, int(xml.attrib["width"])) - - # Make tag ids in each badge unique to combine them into one svg - for tag in ("r", "s"): - content_svg = content_svg.replace(f'id="{tag}"', f'id="{tag}{idx}"') - content_svg = content_svg.replace(f'"url(#{tag})"', f'"url(#{tag}{idx})"') - - badge_svg.extend([f'', content_svg, ""]) - - badge_svg.insert(0, '') - badge_svg.append("") - - with open(os.path.join(BASEDIR, "translation_badge.svg"), "w") as badge_f: - badge_f.write("\n".join(badge_svg)) diff --git a/selfdrive/ui/translations/de.ts b/selfdrive/ui/translations/de.ts deleted file mode 100644 index 28b07029eb..0000000000 --- a/selfdrive/ui/translations/de.ts +++ /dev/null @@ -1,1072 +0,0 @@ - - - - - AbstractAlert - - Close - Schließen - - - Reboot and Update - Aktualisieren und neu starten - - - - AdvancedNetworking - - Back - Zurück - - - Enable Tethering - Tethering aktivieren - - - Tethering Password - Tethering Passwort - - - EDIT - ÄNDERN - - - Enter new tethering password - Neues tethering Passwort eingeben - - - IP Address - IP Adresse - - - Enable Roaming - Roaming aktivieren - - - APN Setting - APN Einstellungen - - - Enter APN - APN eingeben - - - leave blank for automatic configuration - für automatische Konfiguration leer lassen - - - Cellular Metered - Getaktete Verbindung - - - Hidden Network - Verborgenes Netzwerk - - - CONNECT - VERBINDEN - - - Enter SSID - SSID eingeben - - - Enter password - Passwort eingeben - - - for "%1" - für "%1" - - - Prevent large data uploads when on a metered cellular connection - - - - default - - - - metered - - - - unmetered - - - - Wi-Fi Network Metered - - - - Prevent large data uploads when on a metered Wi-Fi connection - - - - - ConfirmationDialog - - Ok - Ok - - - Cancel - Abbrechen - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - Du musst die Nutzungsbedingungen akzeptieren, um Openpilot zu benutzen. - - - Back - Zurück - - - Decline, uninstall %1 - Ablehnen, deinstallieren %1 - - - - DeveloperPanel - - Joystick Debug Mode - Joystick Debug-Modus - - - Longitudinal Maneuver Mode - Längsmanöver-Modus - - - openpilot Longitudinal Control (Alpha) - openpilot Längsregelung (Alpha) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - WARNUNG: Die openpilot Längsregelung befindet sich für dieses Fahrzeug im Alpha-Stadium und deaktiviert das automatische Notbremsen (AEB). - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - Bei diesem Fahrzeug verwendet openpilot standardmäßig den eingebauten Tempomaten anstelle der openpilot Längsregelung. Aktiviere diese Option, um auf die openpilot Längsregelung umzuschalten. Es wird empfohlen, den experimentellen Modus zu aktivieren, wenn die openpilot Längsregelung (Alpha) aktiviert wird. - - - Enable ADB - ADB aktivieren - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB (Android Debug Bridge) ermöglicht die Verbindung zu deinem Gerät über USB oder Netzwerk. Siehe https://docs.comma.ai/how-to/connect-to-comma für weitere Informationen. - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - Nicht verfügbar - - - Serial - Seriennummer - - - Driver Camera - Fahrerkamera - - - PREVIEW - VORSCHAU - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Vorschau der auf den Fahrer gerichteten Kamera, um sicherzustellen, dass die Fahrerüberwachung eine gute Sicht hat. (Fahrzeug muss aus sein) - - - Reset Calibration - Neu kalibrieren - - - RESET - RESET - - - Are you sure you want to reset calibration? - Bist du sicher, dass du die Kalibrierung zurücksetzen möchtest? - - - Review Training Guide - Trainingsanleitung wiederholen - - - REVIEW - TRAINING - - - Review the rules, features, and limitations of openpilot - Wiederhole die Regeln, Fähigkeiten und Limitierungen von Openpilot - - - Are you sure you want to review the training guide? - Bist du sicher, dass du die Trainingsanleitung wiederholen möchtest? - - - Regulatory - Rechtliche Hinweise - - - VIEW - ANSEHEN - - - Change Language - Sprache ändern - - - CHANGE - ÄNDERN - - - Select a language - Sprache wählen - - - Reboot - Neustart - - - Power Off - Ausschalten - - - Your device is pointed %1° %2 and %3° %4. - Deine Geräteausrichtung ist %1° %2 und %3° %4. - - - down - unten - - - up - oben - - - left - links - - - right - rechts - - - Are you sure you want to reboot? - Bist du sicher, dass du das Gerät neu starten möchtest? - - - Disengage to Reboot - Für Neustart deaktivieren - - - Are you sure you want to power off? - Bist du sicher, dass du das Gerät ausschalten möchtest? - - - Disengage to Power Off - Zum Ausschalten deaktivieren - - - Reset - Zurücksetzen - - - Review - Überprüfen - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Koppele dein Gerät mit Comma Connect (connect.comma.ai) und sichere dir dein Comma Prime Angebot. - - - Pair Device - Gerät koppeln - - - PAIR - KOPPELN - - - Disengage to Reset Calibration - - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - -Steering lag calibration is %1% complete. - - - - - -Steering lag calibration is complete. - - - - Steering torque response calibration is %1% complete. - - - - Steering torque response calibration is complete. - - - - - DriverViewWindow - - camera starting - Kamera startet - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - EXPERIMENTELLER MODUS AN - - - CHILL MODE ON - ENTSPANNTER MODUS AN - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - openpilot lernt das Fahren, indem es Menschen wie dir beim Fahren zuschaut. - -Der Firehose-Modus ermöglicht es dir, deine Trainingsdaten-Uploads zu maximieren, um die Fahrmodelle von openpilot zu verbessern. Mehr Daten bedeuten größere Modelle, was zu einem besseren Experimentellen Modus führt. - - - Firehose Mode: ACTIVE - Firehose-Modus: AKTIV - - - ACTIVE - AKTIV - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - Für maximale Effektivität bring dein Gerät jede Woche nach drinnen und verbinde es mit einem guten USB-C-Adapter und WLAN.<br><br>Der Firehose-Modus funktioniert auch während der Fahrt, wenn das Gerät mit einem Hotspot oder einer ungedrosselten SIM-Karte verbunden ist.<br><br><br><b>Häufig gestellte Fragen</b><br><br><i>Spielt es eine Rolle, wie oder wo ich fahre?</i> Nein, fahre einfach wie gewohnt.<br><br><i>Werden im Firehose-Modus alle meine Segmente hochgeladen?</i> Nein, wir wählen selektiv nur einen Teil deiner Segmente aus.<br><br><i>Welcher USB-C-Adapter ist gut?</i> Jedes Schnellladegerät für Handy oder Laptop sollte ausreichen.<br><br><i>Spielt es eine Rolle, welche Software ich nutze?</i> Ja, nur das offizielle Upstream‑openpilot (und bestimmte Forks) kann für das Training verwendet werden. - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>%n Segment</b> deiner Fahrten ist bisher im Trainingsdatensatz. - <b>%n Segmente</b> deiner Fahrten sind bisher im Trainingsdatensatz. - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INAKTIV</span>: Verbinde dich mit einem ungedrosselten Netzwerk - - - Firehose Mode - - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - MAX - - - - InputDialog - - Cancel - Abbrechen - - - Need at least %n character(s)! - - Mindestens %n Buchstabe benötigt! - Mindestens %n Buchstaben benötigt! - - - - - MultiOptionDialog - - Select - Auswählen - - - Cancel - Abbrechen - - - - Networking - - Advanced - Erweitert - - - Enter password - Passwort eingeben - - - for "%1" - für "%1" - - - Wrong password - Falsches Passwort - - - - OffroadAlert - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Stelle sofort eine Internetverbindung her, um nach Updates zu suchen. Wenn du keine Verbindung herstellst, kann openpilot in %1 nicht mehr aktiviert werden. - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - Verbinde dich mit dem Internet, um nach Updates zu suchen. openpilot startet nicht automatisch, bis eine Internetverbindung besteht und nach Updates gesucht wurde. - - - Unable to download updates -%1 - Updates konnten nicht heruntergeladen werden -%1 - - - Taking camera snapshots. System won't start until finished. - Kamera-Snapshots werden aufgenommen. Das System startet erst, wenn dies abgeschlossen ist. - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - Ein Update für das Betriebssystem deines Geräts wird im Hintergrund heruntergeladen. Du wirst aufgefordert, das Update zu installieren, sobald es bereit ist. - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot konnte dein Auto nicht identifizieren. Dein Auto wird entweder nicht unterstützt oder die Steuergeräte (ECUs) werden nicht erkannt. Bitte reiche einen Pull Request ein, um die Firmware-Versionen für das richtige Fahrzeug hinzuzufügen. Hilfe findest du auf discord.comma.ai. - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot hat eine Änderung der Montageposition des Geräts erkannt. Stelle sicher, dass das Gerät vollständig in der Halterung sitzt und die Halterung fest an der Windschutzscheibe befestigt ist. - - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - Gerätetemperatur zu hoch. Das System kühlt ab, bevor es startet. Aktuelle interne Komponententemperatur: %1 - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - - - - Acknowledge Excessive Actuation - - - - Snooze Update - Update pausieren - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - Aktualisieren - - - ALERTS - HINWEISE - - - ALERT - HINWEIS - - - - OnroadAlerts - - openpilot Unavailable - openpilot nicht verfügbar - - - TAKE CONTROL IMMEDIATELY - ÜBERNIMM SOFORT DIE KONTROLLE - - - Reboot Device - Gerät neu starten - - - Waiting to start - Warten auf Start - - - System Unresponsive - System reagiert nicht - - - - PairingPopup - - Pair your device to your comma account - Verbinde dein Gerät mit deinem comma Konto - - - Go to https://connect.comma.ai on your phone - Gehe zu https://connect.comma.ai auf deinem Handy - - - Click "add new device" and scan the QR code on the right - Klicke auf "neues Gerät hinzufügen" und scanne den QR code rechts - - - Bookmark connect.comma.ai to your home screen to use it like an app - Füge connect.comma.ai als Lesezeichen auf deinem Homescreen hinzu um es wie eine App zu verwenden - - - Please connect to Wi-Fi to complete initial pairing - Bitte verbinde dich mit WLAN, um die Koppelung abzuschließen. - - - - ParamControl - - Cancel - Abbrechen - - - Enable - Aktivieren - - - - PrimeAdWidget - - Upgrade Now - Jetzt abonieren - - - Become a comma prime member at connect.comma.ai - Werde Comma Prime Mitglied auf connect.comma.ai - - - PRIME FEATURES: - PRIME FUNKTIONEN: - - - Remote access - Fernzugriff - - - 24/7 LTE connectivity - 24/7 LTE-Verbindung - - - 1 year of drive storage - Fahrdaten-Speicherung für 1 Jahr - - - Remote snapshots - Remote-Snapshots - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ ABBONIERT - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - vor %n Minute - vor %n Minuten - - - - %n hour(s) ago - - vor %n Stunde - vor %n Stunden - - - - %n day(s) ago - - vor %n Tag - vor %n Tagen - - - - now - jetzt - - - - SettingsWindow - - × - x - - - Device - Gerät - - - Network - Netzwerk - - - Toggles - Schalter - - - Software - Software - - - Developer - Entwickler - - - Firehose - Firehose - - - - SetupWidget - - Finish Setup - Einrichtung beenden - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Koppele dein Gerät mit Comma Connect (connect.comma.ai) und sichere dir dein Comma Prime Angebot. - - - Pair device - Gerät koppeln - - - - Sidebar - - CONNECT - This is a brand/service name for comma connect, don't translate - CONNECT - - - OFFLINE - OFFLINE - - - ONLINE - ONLINE - - - ERROR - FEHLER - - - TEMP - TEMP - - - HIGH - HOCH - - - GOOD - GUT - - - OK - OK - - - VEHICLE - FAHRZEUG - - - NO - KEIN - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - WLAN - - - ETH - LAN - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - UNINSTALL - Too long for UI - DEINSTALL - - - Uninstall %1 - Deinstalliere %1 - - - Are you sure you want to uninstall? - Bist du sicher, dass du Openpilot entfernen möchtest? - - - CHECK - ÜBERPRÜFEN - - - Updates are only downloaded while the car is off. - Updates werden nur heruntergeladen, wenn das Auto aus ist. - - - Current Version - Aktuelle Version - - - Download - Download - - - Install Update - Update installieren - - - INSTALL - INSTALLIEREN - - - Target Branch - Ziel Branch - - - SELECT - AUSWÄHLEN - - - Select a branch - Wähle einen Branch - - - Uninstall - Deinstallieren - - - failed to check for update - Update-Prüfung fehlgeschlagen - - - up to date, last checked %1 - Auf dem neuesten Stand, zuletzt geprüft am %1 - - - DOWNLOAD - HERUNTERLADEN - - - update available - Update verfügbar - - - never - nie - - - - SshControl - - SSH Keys - SSH Schlüssel - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Warnung: Dies ermöglicht SSH zugriff für alle öffentlichen Schlüssel in deinen Github Einstellungen. Gib niemals einen anderen Benutzernamen, als deinen Eigenen an. Comma Angestellte fragen dich niemals danach ihren Github Benutzernamen hinzuzufügen. - - - ADD - HINZUFÜGEN - - - Enter your GitHub username - Gib deinen GitHub Benutzernamen ein - - - LOADING - LADEN - - - REMOVE - LÖSCHEN - - - Username '%1' has no keys on GitHub - Benutzername '%1' hat keine Schlüssel auf GitHub - - - Request timed out - Zeitüberschreitung der Anforderung - - - Username '%1' doesn't exist on GitHub - Benutzername '%1' existiert nicht auf GitHub - - - - SshToggle - - Enable SSH - SSH aktivieren - - - - TermsPage - - Decline - Ablehnen - - - Agree - Zustimmen - - - Welcome to openpilot - Willkommen bei openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - Du musst die Nutzungsbedingungen akzeptieren, um openpilot zu verwenden. Lies die aktuellen Bedingungen unter <span style='color: #465BEA;'>https://comma.ai/terms</span>, bevor du fortfährst. - - - - TogglesPanel - - Enable openpilot - Openpilot aktivieren - - - Enable Lane Departure Warnings - Spurverlassenswarnungen aktivieren - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Erhalte Warnungen, zurück in die Spur zu lenken, wenn dein Auto über eine erkannte Fahrstreifenmarkierung ohne aktivierten Blinker mit mehr als 50 km/h fährt. - - - Use Metric System - Benutze das metrische System - - - Display speed in km/h instead of mph. - Zeige die Geschwindigkeit in km/h anstatt von mph. - - - Record and Upload Driver Camera - Fahrerkamera aufnehmen und hochladen - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Lade Daten der Fahreraufmerksamkeitsüberwachungskamera hoch, um die Fahreraufmerksamkeitsüberwachungsalgorithmen zu verbessern. - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Wenn aktiviert, deaktiviert sich Openpilot sobald das Gaspedal betätigt wird. - - - Experimental Mode - Experimenteller Modus - - - Disengage on Accelerator Pedal - Bei Gasbetätigung ausschalten - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - Openpilot fährt standardmäßig im <b>entspannten Modus</b>. Der Experimentelle Modus aktiviert<b>Alpha-level Funktionen</b>, die noch nicht für den entspannten Modus bereit sind. Die experimentellen Funktionen sind die Folgenden: - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Lass das Fahrmodell Gas und Bremse kontrollieren. Openpilot wird so fahren, wie es dies von einem Menschen erwarten würde; inklusive des Anhaltens für Ampeln und Stoppschildern. Da das Fahrmodell entscheidet wie schnell es fährt stellt die gesetzte Geschwindigkeit lediglich das obere Limit dar. Dies ist ein Alpha-level Funktion. Fehler sind zu erwarten. - - - New Driving Visualization - Neue Fahrvisualisierung - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar da es den eingebauten adaptiven Tempomaten des Autos benutzt. - - - Aggressive - Aggressiv - - - Standard - Standard - - - Relaxed - Entspannt - - - Driving Personality - Fahrstil - - - End-to-End Longitudinal Control - Ende-zu-Ende Längsregelung - - - openpilot longitudinal control may come in a future update. - Die openpilot Längsregelung könnte in einem zukünftigen Update verfügbar sein. - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Eine Alpha-Version der openpilot Längsregelung kann zusammen mit dem Experimentellen Modus auf non-stable Branches getestet werden. - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - Aktiviere den Schalter für openpilot Längsregelung (Alpha), um den Experimentellen Modus zu erlauben. - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Standard wird empfohlen. Im aggressiven Modus folgt openpilot vorausfahrenden Fahrzeugen enger und ist beim Gasgeben und Bremsen aggressiver. Im entspannten Modus hält openpilot mehr Abstand zu vorausfahrenden Fahrzeugen. Bei unterstützten Fahrzeugen kannst du mit der Abstandstaste am Lenkrad zwischen diesen Fahrstilen wechseln. - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - Die Fahrvisualisierung wechselt bei niedrigen Geschwindigkeiten auf die nach vorne gerichtete Weitwinkelkamera, um Kurven besser darzustellen. Das Logo des Experimentellen Modus wird außerdem oben rechts angezeigt. - - - Always-On Driver Monitoring - Dauerhaft aktive Fahrerüberwachung - - - Enable driver monitoring even when openpilot is not engaged. - Fahrerüberwachung auch aktivieren, wenn openpilot nicht aktiv ist. - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Record and Upload Microphone Audio - - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - WiFiPromptWidget - - Open - Öffnen - - - Maximize your training data uploads to improve openpilot's driving models. - Maximiere deine Trainingsdaten-Uploads, um die Fahrmodelle von openpilot zu verbessern. - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose-Modus <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - Suche nach Netzwerken... - - - CONNECTING... - VERBINDEN... - - - FORGET - VERGESSEN - - - Forget Wi-Fi Network "%1"? - WLAN Netzwerk "%1" vergessen? - - - Forget - Vergessen - - - diff --git a/selfdrive/ui/translations/en.ts b/selfdrive/ui/translations/en.ts deleted file mode 100644 index fbccbedb20..0000000000 --- a/selfdrive/ui/translations/en.ts +++ /dev/null @@ -1,48 +0,0 @@ - - - - - FirehosePanel - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>%n segment</b> of your driving is in the training dataset so far. - <b>%n segments</b> of your driving are in the training dataset so far. - - - - - InputDialog - - Need at least %n character(s)! - - Need at least %n character! - Need at least %n characters! - - - - - QObject - - %n minute(s) ago - - %n minute ago - %n minutes ago - - - - %n hour(s) ago - - %n hour ago - %n hours ago - - - - %n day(s) ago - - %n day ago - %n days ago - - - - diff --git a/selfdrive/ui/translations/es.ts b/selfdrive/ui/translations/es.ts deleted file mode 100644 index e8d57dddbe..0000000000 --- a/selfdrive/ui/translations/es.ts +++ /dev/null @@ -1,1074 +0,0 @@ - - - - - AbstractAlert - - Close - Cerrar - - - Reboot and Update - Reiniciar y Actualizar - - - - AdvancedNetworking - - Back - Volver - - - Enable Tethering - Activar Tether - - - Tethering Password - Contraseña de Tethering - - - EDIT - EDITAR - - - Enter new tethering password - Nueva contraseña de tethering - - - IP Address - Dirección IP - - - Enable Roaming - Activar Roaming - - - APN Setting - Configuración de APN - - - Enter APN - Insertar APN - - - leave blank for automatic configuration - dejar en blanco para configuración automática - - - Cellular Metered - Plano de datos limitado - - - Hidden Network - Red Oculta - - - CONNECT - CONECTAR - - - Enter SSID - Ingrese SSID - - - Enter password - Ingrese contraseña - - - for "%1" - para "%1" - - - Prevent large data uploads when on a metered cellular connection - Evite cargas de grandes cantidades de datos cuando utilice una conexión celular medida - - - default - por defecto - - - metered - medido - - - unmetered - sin medidor - - - Wi-Fi Network Metered - Red Wi-Fi medida - - - Prevent large data uploads when on a metered Wi-Fi connection - Evite cargas de grandes cantidades de datos cuando esté en una conexión Wi-Fi medida - - - - ConfirmationDialog - - Ok - OK - - - Cancel - Cancelar - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - Debe aceptar los términos y condiciones para poder utilizar openpilot. - - - Back - Atrás - - - Decline, uninstall %1 - Rechazar, desinstalar %1 - - - - DeveloperPanel - - Joystick Debug Mode - Modo de depuración de joystick - - - Longitudinal Maneuver Mode - Modo de maniobra longitudinal - - - openpilot Longitudinal Control (Alpha) - Control longitudinal de openpilot (fase experimental) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB). - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental). - - - Enable ADB - Activar ADB - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB (Android Debug Bridge) permite conectar a su dispositivo por USB o por red. Visite https://docs.comma.ai/how-to/connect-to-comma para más información. - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - N/A - - - Serial - Serial - - - Pair Device - Emparejar Dispositivo - - - PAIR - EMPAREJAR - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Empareja tu dispositivo con comma connect (connect.comma.ai) y reclama tu oferta de comma prime. - - - Driver Camera - Cámara del conductor - - - PREVIEW - VISUALIZAR - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Previsualizar la cámara del conductor para garantizar que la monitorización del sistema tenga buena visibilidad (el vehículo tiene que estar apagado) - - - Reset Calibration - Formatear Calibración - - - RESET - REINICIAR - - - Are you sure you want to reset calibration? - ¿Seguro que quiere formatear la calibración? - - - Reset - Formatear - - - Review Training Guide - Revisar la Guía de Entrenamiento - - - REVIEW - REVISAR - - - Review the rules, features, and limitations of openpilot - Revisar las reglas, características y limitaciones de openpilot - - - Are you sure you want to review the training guide? - ¿Seguro que quiere revisar la guía de entrenamiento? - - - Review - Revisar - - - Regulatory - Regulador - - - VIEW - VER - - - Change Language - Cambiar Idioma - - - CHANGE - CAMBIAR - - - Select a language - Seleccione el idioma - - - Reboot - Reiniciar - - - Power Off - Apagar - - - Your device is pointed %1° %2 and %3° %4. - Su dispositivo está apuntando %1° %2 y %3° %4. - - - down - abajo - - - up - arriba - - - left - izquierda - - - right - derecha - - - Are you sure you want to reboot? - ¿Seguro qué quiere reiniciar? - - - Disengage to Reboot - Desactivar para Reiniciar - - - Are you sure you want to power off? - ¿Seguro qué quiere apagar? - - - Disengage to Power Off - Desactivar para apagar - - - Disengage to Reset Calibration - Desactivar para restablecer la calibración - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - openpilot requiere que el dispositivo esté montado dentro de los 4° hacia la izquierda o la derecha y dentro de los 5° hacia arriba o 9° hacia abajo. - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - Openpilot se calibra continuamente, por lo que rara vez es necesario reiniciarlo. Restablecer la calibración reiniciará Openpilot si el automóvil está encendido. - - - - -Steering lag calibration is %1% complete. - - -La calibración del retraso de dirección está %1% completada. - - - - -Steering lag calibration is complete. - - -La calibración del retraso de la dirección está completa. - - - Steering torque response calibration is %1% complete. - La calibración de la respuesta del par de dirección está %1% completada. - - - Steering torque response calibration is complete. - La calibración de la respuesta del par de dirección está completa. - - - - DriverViewWindow - - camera starting - iniciando cámara - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - MODO EXPERIMENTAL - - - CHILL MODE ON - MODO CHILL - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - openpilot aprende a conducir observando a humanos, como tú, conducir. - -El Modo Firehose te permite maximizar las subidas de datos de entrenamiento para mejorar los modelos de conducción de openpilot. Más datos significan modelos más grandes, lo que significa un mejor Modo Experimental. - - - Firehose Mode: ACTIVE - Modo Firehose: ACTIVO - - - ACTIVE - ACTIVO - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - Para máxima efectividad, traiga su dispositivo adentro y conéctelo a un buen adaptador USB-C y Wi-Fi semanalmente.<br><br>El Modo Firehose también puede funcionar mientras conduce si está conectado a un punto de acceso o tarjeta SIM ilimitada.<br><br><br><b>Preguntas Frecuentes</b><br><br><i>¿Importa cómo o dónde conduzco?</i> No, solo conduzca como lo haría normalmente.<br><br><i>¿Se extraen todos mis segmentos en el Modo Firehose?</i> No, seleccionamos selectivamente un subconjunto de sus segmentos.<br><br><i>¿Qué es un buen adaptador USB-C?</i> Cualquier cargador rápido de teléfono o portátil debería funcionar.<br><br><i>¿Importa qué software ejecuto?</i> Sí, solo el openpilot original (y forks específicos) pueden usarse para el entrenamiento. - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>%n segmento</b> de tu conducción está en el conjunto de datos de entrenamiento hasta ahora. - <b>%n segmentos</b> de tu conducción están en el conjunto de datos de entrenamiento hasta ahora. - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVO</span>: conéctate a una red sin límite de datos - - - Firehose Mode - Modo manguera contra incendios - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - MAX - - - - InputDialog - - Cancel - Cancelar - - - Need at least %n character(s)! - - ¡Necesita mínimo %n caracter! - ¡Necesita mínimo %n caracteres! - - - - - MultiOptionDialog - - Select - Seleccionar - - - Cancel - Cancelar - - - - Networking - - Advanced - Avanzado - - - Enter password - Ingresar contraseña - - - for "%1" - para "%1" - - - Wrong password - Contraseña incorrecta - - - - OffroadAlert - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - La temperatura del dispositivo es muy alta. El sistema se está enfriando antes de iniciar. Temperatura actual del componente interno: %1 - - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Conéctese inmediatamente al internet para buscar actualizaciones. Si no se conecta al internet, openpilot no iniciará en %1 - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - Conectese al internet para buscar actualizaciones. openpilot no iniciará automáticamente hasta conectarse al internet para buscar actualizaciones. - - - Unable to download updates -%1 - Incapaz de descargar actualizaciones. -%1 - - - Taking camera snapshots. System won't start until finished. - Tomando capturas de las cámaras. El sistema no se iniciará hasta que finalice. - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - Se está descargando una actualización del sistema operativo de su dispositivo en segundo plano. Se le pedirá que actualice cuando esté listo para instalarse. - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Por favor haga un pull request para agregar las versiones de firmware del vehículo adecuado. ¿Necesita ayuda? Únase a discord.comma.ai. - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot detectó un cambio en la posición de montaje del dispositivo. Asegúrese de que el dispositivo esté completamente asentado en el soporte y que el soporte esté firmemente asegurado al parabrisas. - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - - - - Acknowledge Excessive Actuation - - - - Snooze Update - Posponer Actualización - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - ACTUALIZAR - - - ALERTS - ALERTAS - - - ALERT - ALERTA - - - - OnroadAlerts - - openpilot Unavailable - openpilot no disponible - - - TAKE CONTROL IMMEDIATELY - TOME CONTROL INMEDIATAMENTE - - - Reboot Device - Reiniciar Dispositivo - - - Waiting to start - Esperando para iniciar - - - System Unresponsive - Systema no responde - - - - PairingPopup - - Pair your device to your comma account - Empareje su dispositivo con su cuenta de comma - - - Go to https://connect.comma.ai on your phone - Vaya a https://connect.comma.ai en su teléfono - - - Click "add new device" and scan the QR code on the right - Seleccione "agregar nuevo dispositivo" y escanee el código QR a la derecha - - - Bookmark connect.comma.ai to your home screen to use it like an app - Añada connect.comma.ai a su pantalla de inicio para usarlo como una aplicación - - - Please connect to Wi-Fi to complete initial pairing - Conéctese a Wi-Fi para completar el emparejamiento inicial - - - - ParamControl - - Enable - Activar - - - Cancel - Cancelar - - - - PrimeAdWidget - - Upgrade Now - Actualizar Ahora - - - Become a comma prime member at connect.comma.ai - Hazte miembro de comma prime en connect.comma.ai - - - PRIME FEATURES: - BENEFICIOS PRIME: - - - Remote access - Acceso remoto - - - 24/7 LTE connectivity - Conectividad LTE 24/7 - - - 1 year of drive storage - 1 año de almacenamiento - - - Remote snapshots - Capturas remotas - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ SUSCRITO - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - now - ahora - - - %n minute(s) ago - - hace %n min - hace %n mins - - - - %n hour(s) ago - - hace %n hora - hace %n horas - - - - %n day(s) ago - - hace %n día - hace %n días - - - - - SettingsWindow - - × - × - - - Device - Dispositivo - - - Network - Red - - - Toggles - Ajustes - - - Software - Software - - - Developer - Desarrollador - - - Firehose - Firehose - - - - SetupWidget - - Finish Setup - Terminar configuración - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Empareje su dispositivo con comma connect (connect.comma.ai) y reclame su oferta de comma prime. - - - Pair device - Emparejar dispositivo - - - - Sidebar - - CONNECT - CONNECT - - - OFFLINE - OFFLINE - - - ONLINE - EN LÍNEA - - - ERROR - ERROR - - - TEMP - TEMP - - - HIGH - ALTA - - - GOOD - BUENA - - - OK - OK - - - VEHICLE - VEHÍCULO - - - NO - SIN - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - Actualizaciones solo se descargan con el auto apagado. - - - Current Version - Versión Actual - - - Download - Descargar - - - CHECK - VERIFICAR - - - Install Update - Actualizar - - - INSTALL - INSTALAR - - - Target Branch - Rama objetivo - - - SELECT - SELECCIONAR - - - Select a branch - Selecione una rama - - - Uninstall %1 - Desinstalar %1 - - - UNINSTALL - DESINSTALAR - - - Are you sure you want to uninstall? - ¿Seguro qué desea desinstalar? - - - Uninstall - Desinstalar - - - failed to check for update - no se pudo buscar actualizaciones - - - DOWNLOAD - DESCARGAR - - - update available - actualización disponible - - - never - nunca - - - up to date, last checked %1 - actualizado, último chequeo %1 - - - - SshControl - - SSH Keys - Clave SSH - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Aviso: Esto otorga acceso SSH a todas las claves públicas en su Github. Nunca ingrese un nombre de usuario de Github que no sea suyo. Un empleado de comma NUNCA le pedirá que añada un usuario de Github que no sea el suyo. - - - ADD - AÑADIR - - - Enter your GitHub username - Ingrese su usuario de GitHub - - - LOADING - CARGANDO - - - REMOVE - ELIMINAR - - - Username '%1' has no keys on GitHub - El usuario "%1” no tiene claves en GitHub - - - Request timed out - Solicitud expirada - - - Username '%1' doesn't exist on GitHub - El usuario '%1' no existe en Github - - - - SshToggle - - Enable SSH - Habilitar SSH - - - - TermsPage - - Decline - Rechazar - - - Agree - Aceptar - - - Welcome to openpilot - Bienvenido a openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - Debe aceptar los Términos y Condiciones para usar openpilot. Lea los términos más recientes en <span style='color: #465BEA;'>https://comma.ai/terms</span> antes de continuar. - - - - TogglesPanel - - Enable openpilot - Activar openpilot - - - Experimental Mode - Modo Experimental - - - Disengage on Accelerator Pedal - Desactivar con el Acelerador - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Cuando esté activado, presionar el acelerador deshabilitará openpilot. - - - Enable Lane Departure Warnings - Activar Avisos de Salida de Carril - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Recibir alertas para volver al carril cuando su vehículo se salga fuera del carril sin que esté activada la señal de giro y esté conduciendo por encima de 50 km/h (31 mph). - - - Always-On Driver Monitoring - Monitoreo Permanente del Conductor - - - Enable driver monitoring even when openpilot is not engaged. - Habilitar el monitoreo del conductor incluso cuando Openpilot no esté activado. - - - Record and Upload Driver Camera - Grabar y Subir Cámara del Conductor - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Subir datos de la cámara del conductor para ayudar a mejorar el algoritmo de monitoreo del conductor. - - - Use Metric System - Usar Sistema Métrico - - - Display speed in km/h instead of mph. - Mostrar velocidad en km/h en vez de mph. - - - Aggressive - Agresivo - - - Standard - Estándar - - - Relaxed - Relajado - - - Driving Personality - Personalidad de conducción - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Se recomienda el modo estándar. En el modo agresivo, openpilot seguirá más cerca a los autos delante suyo y será más agresivo con el acelerador y el freno. En modo relajado, openpilot se mantendrá más alejado de los autos delante suyo. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>funcionalidades en fase experimental</b>, que no están listas para el modo chill. Las funcionalidades del modo expeimental están listados abajo: - - - End-to-End Longitudinal Control - Control Longitudinal de Punta a Punta - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Dajar que el modelo de conducción controle la aceleración y el frenado. openpilot conducirá como piensa que lo haría una persona, incluiyendo parar en los semáforos en rojo y las señales de alto. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida solo actuará como el límite superior. Este recurso aún está en fase experimental; deberían esperarse errores. - - - New Driving Visualization - Nueva Visualización de la conducción - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - La visualización de la conducción cambiará a la cámara que enfoca la carretera a velocidades bajas para mostrar mejor los giros. El logo del modo experimental también se mostrará en la esquina superior derecha. - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - El modo Experimental no está disponible actualmente para este auto, ya que el ACC default del auto está siendo usado para el control longitudinal. - - - openpilot longitudinal control may come in a future update. - El control longitudinal de openpilot podrá llegar en futuras actualizaciones. - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Se puede probar una versión experimental del control longitudinal openpilot, junto con el modo Experimental, en ramas no liberadas. - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - Activar el control longitudinal (fase experimental) para permitir el modo Experimental. - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - Utilice el sistema openpilot para el control de crucero adaptativo y la asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. - - - Changing this setting will restart openpilot if the car is powered on. - Cambiar esta configuración reiniciará Openpilot si el automóvil está encendido. - - - Record and Upload Microphone Audio - Grabar y cargar audio de micrófono - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - Graba y almacena el audio del micrófono mientras conduces. El audio se incluirá en el video de la cámara del tablero en comma connect. - - - - WiFiPromptWidget - - Open - Abrir - - - Maximize your training data uploads to improve openpilot's driving models. - Maximice sus cargas de datos de entrenamiento para mejorar los modelos de conducción de openpilot. - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Modo Firehose <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - Buscando redes... - - - CONNECTING... - CONECTANDO... - - - FORGET - OLVIDAR - - - Forget Wi-Fi Network "%1"? - ¿Olvidar la Red de Wi-Fi "%1"? - - - Forget - Olvidar - - - diff --git a/selfdrive/ui/translations/fr.ts b/selfdrive/ui/translations/fr.ts deleted file mode 100644 index 4efb92d0c8..0000000000 --- a/selfdrive/ui/translations/fr.ts +++ /dev/null @@ -1,1068 +0,0 @@ - - - - - AbstractAlert - - Close - Fermer - - - Reboot and Update - Redémarrer et mettre à jour - - - - AdvancedNetworking - - Back - Retour - - - Enable Tethering - Activer le partage de connexion - - - Tethering Password - Mot de passe du partage de connexion - - - EDIT - MODIFIER - - - Enter new tethering password - Entrez le nouveau mot de passe du partage de connexion - - - IP Address - Adresse IP - - - Enable Roaming - Activer l'itinérance - - - APN Setting - Paramètre APN - - - Enter APN - Entrer le nom du point d'accès - - - leave blank for automatic configuration - laisser vide pour une configuration automatique - - - Cellular Metered - Connexion cellulaire limitée - - - Hidden Network - Réseau Caché - - - CONNECT - CONNECTER - - - Enter SSID - Entrer le SSID - - - Enter password - Entrer le mot de passe - - - for "%1" - pour "%1" - - - Prevent large data uploads when on a metered cellular connection - - - - default - - - - metered - - - - unmetered - - - - Wi-Fi Network Metered - - - - Prevent large data uploads when on a metered Wi-Fi connection - - - - - ConfirmationDialog - - Ok - Ok - - - Cancel - Annuler - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - Vous devez accepter les conditions générales pour utiliser openpilot. - - - Back - Retour - - - Decline, uninstall %1 - Refuser, désinstaller %1 - - - - DeveloperPanel - - Joystick Debug Mode - Mode débogage au joystick - - - Longitudinal Maneuver Mode - Mode manœuvre longitudinale - - - openpilot Longitudinal Control (Alpha) - Contrôle longitudinal openpilot (Alpha) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - ATTENTION : le contrôle longitudinal openpilot est en alpha pour cette voiture et désactivera le freinage d'urgence automatique (AEB). - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - Sur cette voiture, openpilot utilise par défaut le régulateur de vitesse adaptatif intégré à la voiture plutôt que le contrôle longitudinal d'openpilot. Activez ceci pour passer au contrôle longitudinal openpilot. Il est recommandé d'activer le mode expérimental lors de l'activation du contrôle longitudinal openpilot alpha. - - - Enable ADB - - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - N/A - - - Serial - N° de série - - - Driver Camera - Caméra conducteur - - - PREVIEW - APERÇU - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Aperçu de la caméra orientée vers le conducteur pour assurer une bonne visibilité de la surveillance du conducteur. (véhicule doit être éteint) - - - Reset Calibration - Réinitialiser la calibration - - - RESET - RÉINITIALISER - - - Are you sure you want to reset calibration? - Êtes-vous sûr de vouloir réinitialiser la calibration ? - - - Reset - Réinitialiser - - - Review Training Guide - Revoir le guide de formation - - - REVIEW - REVOIR - - - Review the rules, features, and limitations of openpilot - Revoir les règles, fonctionnalités et limitations d'openpilot - - - Are you sure you want to review the training guide? - Êtes-vous sûr de vouloir revoir le guide de formation ? - - - Review - Revoir - - - Regulatory - Réglementaire - - - VIEW - VOIR - - - Change Language - Changer de langue - - - CHANGE - CHANGER - - - Select a language - Choisir une langue - - - Reboot - Redémarrer - - - Power Off - Éteindre - - - Your device is pointed %1° %2 and %3° %4. - Votre appareil est orienté %1° %2 et %3° %4. - - - down - bas - - - up - haut - - - left - gauche - - - right - droite - - - Are you sure you want to reboot? - Êtes-vous sûr de vouloir redémarrer ? - - - Disengage to Reboot - Désengager pour redémarrer - - - Are you sure you want to power off? - Êtes-vous sûr de vouloir éteindre ? - - - Disengage to Power Off - Désengager pour éteindre - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Associez votre appareil avec comma connect (connect.comma.ai) et profitez de l'offre comma prime. - - - Pair Device - Associer l'appareil - - - PAIR - ASSOCIER - - - Disengage to Reset Calibration - - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - -Steering lag calibration is %1% complete. - - - - - -Steering lag calibration is complete. - - - - Steering torque response calibration is %1% complete. - - - - Steering torque response calibration is complete. - - - - - DriverViewWindow - - camera starting - démarrage de la caméra - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - MODE EXPÉRIMENTAL ACTIVÉ - - - CHILL MODE ON - MODE DÉTENTE ACTIVÉ - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - - - Firehose Mode: ACTIVE - - - - ACTIVE - - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - - - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - - - - Firehose Mode - - - - - HudRenderer - - km/h - km/h - - - mph - mi/h - - - MAX - MAX - - - - InputDialog - - Cancel - Annuler - - - Need at least %n character(s)! - - Besoin d'au moins %n caractère ! - Besoin d'au moins %n caractères ! - - - - - MultiOptionDialog - - Select - Sélectionner - - - Cancel - Annuler - - - - Networking - - Advanced - Avancé - - - Enter password - Entrer le mot de passe - - - for "%1" - pour "%1" - - - Wrong password - Mot de passe incorrect - - - - OffroadAlert - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - Température de l'appareil trop élevée. Le système doit refroidir avant de démarrer. Température actuelle de l'appareil : %1 - - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Connectez-vous immédiatement à internet pour vérifier les mises à jour. Si vous ne vous connectez pas à internet, openpilot ne s'engagera pas dans %1 - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - Connectez l'appareil à internet pour vérifier les mises à jour. openpilot ne démarrera pas automatiquement tant qu'il ne se connecte pas à internet pour vérifier les mises à jour. - - - Unable to download updates -%1 - Impossible de télécharger les mises à jour -%1 - - - Taking camera snapshots. System won't start until finished. - Capture de clichés photo. Le système ne démarrera pas tant qu'il n'est pas terminé. - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - Une mise à jour du système d'exploitation de votre appareil est en cours de téléchargement en arrière-plan. Vous serez invité à effectuer la mise à jour lorsqu'elle sera prête à être installée. - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot n'a pas pu identifier votre voiture. Votre voiture n'est pas supportée ou ses ECUs ne sont pas reconnues. Veuillez soumettre un pull request pour ajouter les versions de firmware au véhicule approprié. Besoin d'aide ? Rejoignez discord.comma.ai. - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot a détecté un changement dans la position de montage de l'appareil. Assurez-vous que l'appareil est totalement inséré dans le support et que le support est fermement fixé au pare-brise. - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - - - - Acknowledge Excessive Actuation - - - - Snooze Update - Reporter la mise à jour - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - MISE À JOUR - - - ALERTS - ALERTES - - - ALERT - ALERTE - - - - OnroadAlerts - - openpilot Unavailable - openpilot indisponible - - - TAKE CONTROL IMMEDIATELY - REPRENEZ LE CONTRÔLE IMMÉDIATEMENT - - - Reboot Device - Redémarrer l'appareil - - - Waiting to start - En attente de démarrage - - - System Unresponsive - Système inopérant - - - - PairingPopup - - Pair your device to your comma account - Associez votre appareil à votre compte comma - - - Go to https://connect.comma.ai on your phone - Allez sur https://connect.comma.ai sur votre téléphone - - - Click "add new device" and scan the QR code on the right - Cliquez sur "ajouter un nouvel appareil" et scannez le code QR à droite - - - Bookmark connect.comma.ai to your home screen to use it like an app - Ajoutez connect.comma.ai à votre écran d'accueil pour l'utiliser comme une application - - - Please connect to Wi-Fi to complete initial pairing - Connectez-vous au Wi-Fi pour terminer l'appairage initial - - - - ParamControl - - Enable - Activer - - - Cancel - Annuler - - - - PrimeAdWidget - - Upgrade Now - Mettre à niveau - - - Become a comma prime member at connect.comma.ai - Devenez membre comma prime sur connect.comma.ai - - - PRIME FEATURES: - FONCTIONNALITÉS PRIME : - - - Remote access - Accès à distance - - - 24/7 LTE connectivity - Connexion LTE 24/7 - - - 1 year of drive storage - 1 an de stockage de trajets - - - Remote snapshots - Captures à distance - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ ABONNÉ - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - il y a %n minute - il y a %n minutes - - - - %n hour(s) ago - - il y a %n heure - il y a %n heures - - - - %n day(s) ago - - il y a %n jour - il y a %n jours - - - - now - maintenant - - - - SettingsWindow - - × - × - - - Device - Appareil - - - Network - Réseau - - - Toggles - Options - - - Software - Logiciel - - - Developer - Dév. - - - Firehose - - - - - SetupWidget - - Finish Setup - Terminer l'installation - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Associez votre appareil avec comma connect (connect.comma.ai) et profitez de l'offre comma prime. - - - Pair device - Associer l'appareil - - - - Sidebar - - CONNECT - CONNECTER - - - OFFLINE - HORS LIGNE - - - ONLINE - EN LIGNE - - - ERROR - ERREUR - - - TEMP - TEMP - - - HIGH - HAUT - - - GOOD - BON - - - OK - OK - - - VEHICLE - VÉHICULE - - - NO - NON - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - Les MàJ sont téléchargées uniquement si la voiture est éteinte. - - - Current Version - Version actuelle - - - Download - Télécharger - - - CHECK - VÉRIFIER - - - Install Update - Installer la mise à jour - - - INSTALL - INSTALLER - - - Target Branch - Branche cible - - - SELECT - SÉLECTIONNER - - - Select a branch - Sélectionner une branche - - - Uninstall %1 - Désinstaller %1 - - - UNINSTALL - DÉSINSTALLER - - - Are you sure you want to uninstall? - Êtes-vous sûr de vouloir désinstaller ? - - - Uninstall - Désinstaller - - - failed to check for update - échec de la vérification de la mise à jour - - - DOWNLOAD - TÉLÉCHARGER - - - update available - mise à jour disponible - - - never - jamais - - - up to date, last checked %1 - à jour, dernière vérification %1 - - - - SshControl - - SSH Keys - Clés SSH - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Attention : Ceci accorde l'accès SSH à toutes les clés publiques de vos paramètres GitHub. N'entrez jamais un nom d'utilisateur GitHub autre que le vôtre. Un employé de comma ne vous demandera JAMAIS d'ajouter son nom d'utilisateur GitHub. - - - ADD - AJOUTER - - - Enter your GitHub username - Entrez votre nom d'utilisateur GitHub - - - LOADING - CHARGEMENT - - - REMOVE - SUPPRIMER - - - Username '%1' has no keys on GitHub - L'utilisateur '%1' n'a pas de clés sur GitHub - - - Request timed out - Délai de la demande dépassé - - - Username '%1' doesn't exist on GitHub - L'utilisateur '%1' n'existe pas sur GitHub - - - - SshToggle - - Enable SSH - Activer SSH - - - - TermsPage - - Decline - Refuser - - - Agree - Accepter - - - Welcome to openpilot - - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - - - - - TogglesPanel - - Enable openpilot - Activer openpilot - - - Experimental Mode - Mode expérimental - - - Disengage on Accelerator Pedal - Désengager avec la pédale d'accélérateur - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Lorsqu'il est activé, appuyer sur la pédale d'accélérateur désengagera openpilot. - - - Enable Lane Departure Warnings - Activer les avertissements de sortie de voie - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Recevez des alertes pour revenir dans la voie lorsque votre véhicule dérive au-delà d'une ligne de voie détectée sans clignotant activé en roulant à plus de 31 mph (50 km/h). - - - Record and Upload Driver Camera - Enregistrer et télécharger la caméra conducteur - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Publiez les données de la caméra orientée vers le conducteur et aidez à améliorer l'algorithme de surveillance du conducteur. - - - Use Metric System - Utiliser le système métrique - - - Display speed in km/h instead of mph. - Afficher la vitesse en km/h au lieu de mph. - - - Aggressive - Aggressif - - - Standard - Standard - - - Relaxed - Détendu - - - Driving Personality - Personnalité de conduite - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - Par défaut, openpilot conduit en <b>mode détente</b>. Le mode expérimental permet d'activer des <b>fonctionnalités alpha</b> qui ne sont pas prêtes pour le mode détente. Les fonctionnalités expérimentales sont listées ci-dessous : - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Laissez le modèle de conduite contrôler l'accélérateur et les freins. openpilot conduira comme il pense qu'un humain le ferait, y compris s'arrêter aux feux rouges et aux panneaux stop. Comme le modèle de conduite décide de la vitesse à adopter, la vitesse définie ne servira que de limite supérieure. Cette fonctionnalité est de qualité alpha ; des erreurs sont à prévoir. - - - New Driving Visualization - Nouvelle visualisation de la conduite - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - Le mode expérimental est actuellement indisponible pour cette voiture car le régulateur de vitesse adaptatif d'origine est utilisé pour le contrôle longitudinal. - - - openpilot longitudinal control may come in a future update. - Le contrôle longitudinal openpilot pourrait être disponible dans une future mise à jour. - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Une version alpha du contrôle longitudinal openpilot peut être testée, avec le mode expérimental, sur des branches non publiées. - - - End-to-End Longitudinal Control - Contrôle longitudinal de bout en bout - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - Activer le contrôle longitudinal d'openpilot (en alpha) pour autoriser le mode expérimental. - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Le mode Standard est recommandé. En mode Agressif, openpilot suivra les véhicules de plus près et sera plus dynamique avec l'accélérateur et le frein. En mode Détendu, openpilot maintiendra une distance plus importante avec les véhicules qui précèdent. Sur les véhicules compatibles, vous pouvez alterner entre ces personnalités à l'aide du bouton de distance au volant. - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - La visualisation de la conduite passera sur la caméra grand angle dirigée vers la route à faible vitesse afin de mieux montrer certains virages. Le logo du mode expérimental s'affichera également dans le coin supérieur droit. - - - Always-On Driver Monitoring - Surveillance continue du conducteur - - - Enable driver monitoring even when openpilot is not engaged. - Activer la surveillance conducteur lorsque openpilot n'est pas actif. - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Record and Upload Microphone Audio - - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - WiFiPromptWidget - - Open - - - - Maximize your training data uploads to improve openpilot's driving models. - - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - - WifiUI - - Scanning for networks... - Recherche de réseaux... - - - CONNECTING... - CONNEXION... - - - FORGET - OUBLIER - - - Forget Wi-Fi Network "%1"? - Oublier le réseau Wi-Fi "%1" ? - - - Forget - Oublier - - - diff --git a/selfdrive/ui/translations/ja.ts b/selfdrive/ui/translations/ja.ts deleted file mode 100644 index 4307cee91f..0000000000 --- a/selfdrive/ui/translations/ja.ts +++ /dev/null @@ -1,1069 +0,0 @@ - - - - - AbstractAlert - - Close - 閉じる - - - Reboot and Update - 再起動してアップデート - - - - AdvancedNetworking - - Back - 戻る - - - Enable Tethering - テザリング有効 - - - Tethering Password - テザリングパスワード - - - EDIT - 編集 - - - Enter new tethering password - 新しいテザリングパスワードを入力 - - - IP Address - IPアドレス - - - Enable Roaming - ローミング有効 - - - APN Setting - APN設定 - - - Enter APN - APNを入力 - - - leave blank for automatic configuration - 自動で設定するには空白のままにしてください - - - Cellular Metered - 従量制通信設定 - - - Hidden Network - ネットワーク非表示 - - - CONNECT - 接続 - - - Enter SSID - SSIDを入力 - - - Enter password - パスワードを入力 - - - for "%1" - [%1] - - - Prevent large data uploads when on a metered cellular connection - モバイルデータ回線を使用しているときは大容量データをアップロードしません - - - default - 標準設定 - - - metered - 従量制 - - - unmetered - 定額制 - - - Wi-Fi Network Metered - 従量制のWi-Fiネットワーク - - - Prevent large data uploads when on a metered Wi-Fi connection - 通信制限のあるWi-Fi接続では大容量データをアップロードしません - - - - ConfirmationDialog - - Ok - OK - - - Cancel - キャンセル - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - openpilotを使用するためには利用規約に同意する必要があります - - - Back - 戻る - - - Decline, uninstall %1 - 同意しない(%1をアンインストール) - - - - DeveloperPanel - - Joystick Debug Mode - ジョイスティックデバッグモード - - - Longitudinal Maneuver Mode - アクセル制御マニューバー - - - openpilot Longitudinal Control (Alpha) - openpilotアクセル制御(Alpha) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - この車ではopenpilotのアクセル制御はアルファ版であり、自動緊急ブレーキ(AEB)が無効化されます。 - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - この車では、openpilotは車両内蔵のACC(アダプティブクルーズコントロール)をデフォルトとして使用し、openpilotのアクセル制御は無効化されています。アクセル制御をopenpilotに切り替えるにはこの設定を有効にしてください。また同時にExperimentalモードを推奨します。 - - - Enable ADB - ADBを有効にする - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB(Android Debug Bridge)により、USBまたはネットワーク経由でデバイスに接続できます。詳細は、https://docs.comma.ai/how-to/connect-to-comma を参照してください。 - - - - DevicePanel - - Dongle ID - ドングルID - - - N/A - 該当なし - - - Serial - シリアル番号 - - - Driver Camera - 車内カメラ - - - PREVIEW - プレビュー - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - 車内カメラでドライバー監視システムのカメラ画像を確認できます。(車両のパワーOFF時の機能です) - - - Reset Calibration - キャリブレーションリセット - - - RESET - リセット - - - Are you sure you want to reset calibration? - キャリブレーションをリセットしますか? - - - Review Training Guide - トレーニングガイドを見る - - - REVIEW - 確認 - - - Review the rules, features, and limitations of openpilot - openpilotのルール、機能、および制限を確認してください - - - Are you sure you want to review the training guide? - トレーニングガイドを始めてもよろしいですか? - - - Regulatory - 規約 - - - VIEW - 確認 - - - Change Language - 多言語対応 - - - CHANGE - 変更 - - - Select a language - 言語を選択 - - - Reboot - 再起動 - - - Power Off - パワーオフ - - - Your device is pointed %1° %2 and %3° %4. - このデバイスは%2 %1°、%4 %3°の向きに設置されています。 - - - down - - - - up - - - - left - - - - right - - - - Are you sure you want to reboot? - 再起動してもよろしいですか? - - - Disengage to Reboot - 再起動するには車を一旦停止してください - - - Are you sure you want to power off? - パワーオフしてもよろしいですか? - - - Disengage to Power Off - パワーオフするには車を一旦停止してください - - - Reset - リセット - - - Review - 見る - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - デバイスをcommaコネクト(connect.comma.ai)でペアリングしてcommaプライムの特典を受け取ってください。 - - - Pair Device - デバイスのペアリング - - - PAIR - OK - - - Disengage to Reset Calibration - キャリブレーションをリセットするには運転支援を解除して下さい。 - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - openpilotの本体は左右4°以内、上5°下9°以内の角度で取付ける必要があります。 - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - openpilot は継続的にキャリブレーションを行っており、リセットが必要になることはほとんどありません。キャリブレーションをリセットすると、車の電源が入っている場合はopenpilotが再起動します。 - - - - -Steering lag calibration is %1% complete. - - -ステアリング遅延のキャリブレーションが%1%完了。 - - - - -Steering lag calibration is complete. - - -ステアリング遅延のキャリブレーション完了。 - - - Steering torque response calibration is %1% complete. - ステアリングトルク応答のキャリブレーションが%1%完了。 - - - Steering torque response calibration is complete. - ステアリングトルク応答のキャリブレーション完了。 - - - - DriverViewWindow - - camera starting - カメラ起動中 - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - EXPERIMENTALモード - - - CHILL MODE ON - CHILLモード - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - openpilotは人間であるあなたの運転から学び、AI学習します。 - -Firehoseモードを有効にすると学習データを最大限アップロードし、openpilotの運転モデルを改善することができます。より多くのデータはより大きなモデルとなり、Experimentalモードの精度を向上させます。 - - - Firehose Mode: ACTIVE - Firehoseモード: 作動中 - - - ACTIVE - 動作中 - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - 最大の効果を得るためにはデバイスを屋内に持ち込み、大容量のUSB-C充電器とWi-Fiに毎週接続してください。<br><br>Firehoseモードは公衆無線LANや大容量契約のSIMカードに接続していれば、運転中でも動作します。<br><br><br><b>よくある質問(FAQ)</b><br><br><i>運転のやり方や走る場所は重要ですか?</i> いいえ、普段どおりに運転するだけで大丈夫です。<br><br><i>Firehoseモードでは全てのデータがアップロードされますか?</i> いいえ、アップロードするデータを選ぶことができます。<br><br><i>大容量のUSB-C充電器とは何ですか?</i> スマートフォンやノートパソコンを高速に充電できるものを使って下さい。<br><br><i>どのフォークを使うかは重要ですか?</i>はい、トレーニングには公式のopenpilot(および特定のフォーク)のみが使用できます。 - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - あなたの運転の<b>%nセグメント</b>がこれまでのトレーニングデータに含まれています。 - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>動作停止</span>: 大容量のネットワークに接続してください - - - Firehose Mode - Firehoseモード - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - 最大速度 - - - - InputDialog - - Cancel - キャンセル - - - Need at least %n character(s)! - - %n文字以上にして下さい! - - - - - MultiOptionDialog - - Select - 選択 - - - Cancel - キャンセル - - - - Networking - - Advanced - 詳細 - - - Enter password - パスワードを入力 - - - for "%1" - [%1] - - - Wrong password - パスワードが違います - - - - OffroadAlert - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - インターネットへ接続してアップデートを確認してください。未接続のままではopenpilotを使用できなくなります。あと[%1] - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - インターネットに接続してアップデートを確認してください。接続するまでopenpilotは使用できません。 - - - Unable to download updates -%1 - 更新をダウンロードできませんでした -%1 - - - Taking camera snapshots. System won't start until finished. - スナップショットを撮影中です。完了するまでシステムは起動しません。 - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - オペレーティングシステムがバックグラウンドでダウンロードされています。インストールの準備が整うと更新を促されます。 - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilotが車両を識別できませんでした。車が未対応またはECUが認識されていない可能性があります。該当車両のファームウェアバージョンを追加するためにプルリクエストしてください。サポートが必要な場合は discord.comma.ai に参加することができます。 - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilotがデバイスの取り付け位置にずれを検出しました。デバイスの固定とマウントがフロントガラスにしっかりと取り付けられていることを確認してください。 - - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - デバイスの温度が高すぎるためシステム起動前の冷却中です。現在のデバイス内部温度: %1 - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - 製品のcomma.aiへの登録に失敗しました。このデバイスはcomma.aiのサーバーに接続したりアップロードを行ったりすることはできず、comma.aiからのサポートも受けられません。もしcomma.ai/shopで購入した場合は、https://comma.ai/support にてサポートチケットをご提出ください。 - - - Acknowledge Excessive Actuation - 過剰な作動の検知 - - - Snooze Update - また後で更新する - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - 更新 - - - ALERTS - 警告 - - - ALERT - 警告 - - - - OnroadAlerts - - openpilot Unavailable - openpilotは使用できません - - - TAKE CONTROL IMMEDIATELY - 直ちに車の運転に戻って下さい - - - Reboot Device - デバイスを再起動してください - - - Waiting to start - 始動を待機しています - - - System Unresponsive - システムが応答しません - - - - PairingPopup - - Pair your device to your comma account - デバイスとcommaアカウントを連携して下さい - - - Go to https://connect.comma.ai on your phone - スマートフォンで https://connect.comma.ai にアクセスしてください - - - Click "add new device" and scan the QR code on the right - 「add new device」を押して右側のQRコードをスキャンしてください - - - Bookmark connect.comma.ai to your home screen to use it like an app - connect.comma.aiのサイトをホーム画面に追加して、アプリのように使うことができます。 - - - Please connect to Wi-Fi to complete initial pairing - 最初にペアリングするため、Wi-Fiに接続してください - - - - ParamControl - - Cancel - キャンセル - - - Enable - 有効にする - - - - PrimeAdWidget - - Upgrade Now - 今すぐアップグレード - - - Become a comma prime member at connect.comma.ai - connect.comma.ai からプライム会員に登録できます - - - PRIME FEATURES: - 特典: - - - Remote access - リモートアクセス - - - 24/7 LTE connectivity - 24時間365日のLTE接続 - - - 1 year of drive storage - 1年間分のドライブストレージ - - - Remote snapshots - リモートスナップショット - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ 有効です - - - comma prime - commaプライム - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - %n分前 - - - - %n hour(s) ago - - %n時間前 - - - - %n day(s) ago - - %n日前 - - - - now - たった今 - - - - SettingsWindow - - × - × - - - Device - デバイス - - - Network - ネット - - - Toggles - 機能 - - - Software - ソフト - - - Developer - 開発 - - - Firehose - データ学習 - - - - SetupWidget - - Finish Setup - セットアップの完了 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - デバイスをcommaコネクト(connect.comma.ai)でペアリングしてcommaプライムの特典を受け取ってください。 - - - Pair device - デバイスのペアリング - - - - Sidebar - - CONNECT - 接続 - - - OFFLINE - オフライン - - - ONLINE - オンライン - - - ERROR - エラー - - - TEMP - 温度 - - - HIGH - 高温 - - - GOOD - 最適 - - - OK - OK - - - VEHICLE - 車両 - - - NO - NO - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - 車の電源がオフの間のみアップデートがダウンロードできます。 - - - Current Version - 現在のバージョン - - - Download - ダウンロード - - - Install Update - アップデート - - - INSTALL - インストール - - - Target Branch - 対象のブランチ - - - SELECT - 選択 - - - Select a branch - ブランチを選択 - - - UNINSTALL - 実行 - - - Uninstall %1 - %1をアンインストール - - - Are you sure you want to uninstall? - アンインストールしてもよろしいですか? - - - CHECK - 確認 - - - Uninstall - アンインストール - - - failed to check for update - アップデートの確認に失敗しました。 - - - up to date, last checked %1 - 最新の状態です。最終確認日時:%1 - - - DOWNLOAD - ダウンロード - - - update available - アップデートが利用可能です - - - never - 無効 - - - - SshControl - - SSH Keys - SSH 鍵 - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - 警告: これはGitHubの設定にあるすべての公開鍵への SSH アクセスを許可するものです。自分以外のGitHubユーザー名を入力しないでください。commaのスタッフがGitHubのユーザー名を追加するようお願いすることはありません。 - - - ADD - 追加 - - - Enter your GitHub username - GitHubのユーザー名を入力してください - - - LOADING - 読み込み中 - - - REMOVE - 削除 - - - Username '%1' has no keys on GitHub - ユーザー名“%1”は GitHub に公開鍵がありません - - - Request timed out - リクエストタイムアウト - - - Username '%1' doesn't exist on GitHub - ユーザー名”%1”は GitHub に存在しません - - - - SshToggle - - Enable SSH - SSHの有効化 - - - - TermsPage - - Decline - 拒否 - - - Agree - 同意 - - - Welcome to openpilot - openpilotへようこそ - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - openpilotを使用するには利用規約に同意する必要があります。続行する前に最新の規約を以下でご確認ください: <span style='color: #465BEA;'>https://comma.ai/terms</span> - - - - TogglesPanel - - Enable openpilot - openpilotを有効化 - - - Enable Lane Departure Warnings - 車線逸脱警報の有効化 - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - 時速31マイル(50km)以上のスピードで走行中、ウインカーを作動させずに検出したレーン上に車両が触れた場合、手動で車線内に戻るように警告を行います。 - - - Use Metric System - メートル法の使用 - - - Display speed in km/h instead of mph. - 速度は mph ではなく km/h で表示されます。 - - - Record and Upload Driver Camera - 車内カメラの録画とアップロード - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - 車内カメラの映像をアップロードし、ドライバー監視システムのアルゴリズムの向上に役立てます。 - - - Disengage on Accelerator Pedal - アクセルを踏むと運転サポートを中断 - - - When enabled, pressing the accelerator pedal will disengage openpilot. - この機能を有効化すると、openpilotを利用中にアクセルを踏むとopenpilotによる運転サポートを中断します。 - - - Experimental Mode - Experimentalモード - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilotは標準ではゆっくりとくつろげる運転を提供します。このExperimental(実験)モードを有効にすると、以下のアグレッシブな開発中の機能を利用する事ができます。 - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - openpilotにアクセルとブレーキを任せます。openpilotは赤信号や一時停止サインでの停止を含み、人間と同じように考えて運転を行います。openpilotが運転速度を決定するため、あなたが設定する速度は上限速度になります。この機能は実験段階のため、openpilotの運転ミスに常に備えて注意してください。 - - - New Driving Visualization - 新しい運転画面 - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - 車両の標準ACC(アダプティブ・クルーズ・コントロール)がアクセル制御に使用されているため、現在Experimentalモードは利用できません。 - - - Aggressive - アグレッシブ - - - Standard - 標準 - - - Relaxed - リラックス - - - Driving Personality - 運転傾向 - - - End-to-End Longitudinal Control - End-to-Endアクセル制御 - - - openpilot longitudinal control may come in a future update. - openpilotのアクセル制御は将来のアップデートで利用できる可能性があります。 - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - openpilotのアルファ版アクセル制御は、Experimentalモードと共に非リリースのブランチでテストすることができます。 - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - openpilotのアクセル制御機能(アルファ)を有効にして、Experimentalモードを許可してください。 - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 標準モードが推奨されます。アグレッシブモードではopenpilotは先行車に近づいて追従し、アクセルとブレーキがより強気になります。リラックスモードではopenpilotは先行車から距離を取って走行します。サポートされている車両ではステアリングホイールの距離ボタンでこれらのモードを切り替えることができます。 - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - 運転時の画面効果として、低速時にカーブをより良く表示するために道路用の広角カメラに切り替わります。またExperimentalモードのロゴが右上隅に表示されます。 - - - Always-On Driver Monitoring - 運転者の常時モニタリング - - - Enable driver monitoring even when openpilot is not engaged. - openpilotが作動していない場合でも運転者モニタリングを有効にする。 - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - openpilotシステムを使用してアダプティブクルーズコントロールおよび車線維持支援を行います。システム使用中は常にドライバーが事故を起こさないように注意を払ってください。 - - - Changing this setting will restart openpilot if the car is powered on. - この設定を変更すると車の電源が入っている場合はopenpilotが再起動します。 - - - Record and Upload Microphone Audio - マイク音声の録音とアップロード - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - 運転中にマイク音声を録音・保存します。音声は comma connect のドライブレコーダー映像に含まれます。 - - - - WiFiPromptWidget - - Open - 開く - - - Maximize your training data uploads to improve openpilot's driving models. - openpilotの運転モデルを改善するために、大容量の学習データをアップロードして下さい。 - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehoseモード <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - ネットワークをスキャン中... - - - CONNECTING... - 接続中... - - - FORGET - 削除 - - - Forget Wi-Fi Network "%1"? - Wi-Fiネットワーク%1を削除してもよろしいですか? - - - Forget - 削除 - - - diff --git a/selfdrive/ui/translations/ko.ts b/selfdrive/ui/translations/ko.ts deleted file mode 100644 index 9ab43dd9b8..0000000000 --- a/selfdrive/ui/translations/ko.ts +++ /dev/null @@ -1,1069 +0,0 @@ - - - - - AbstractAlert - - Close - 닫기 - - - Reboot and Update - 업데이트 및 재부팅 - - - - AdvancedNetworking - - Back - 뒤로 - - - Enable Tethering - 테더링 사용 - - - Tethering Password - 테더링 비밀번호 - - - EDIT - 편집 - - - Enter new tethering password - 새 테더링 비밀번호를 입력하세요 - - - IP Address - IP 주소 - - - Enable Roaming - 로밍 사용 - - - APN Setting - APN 설정 - - - Enter APN - APN 입력 - - - leave blank for automatic configuration - 자동 설정하려면 빈 칸으로 두세요 - - - Cellular Metered - 모바일 데이터 종량제 - - - Hidden Network - 숨겨진 네트워크 - - - CONNECT - 연결됨 - - - Enter SSID - SSID 입력 - - - Enter password - 비밀번호를 입력하세요 - - - for "%1" - "%1"에 접속하려면 비밀번호가 필요합니다 - - - Prevent large data uploads when on a metered cellular connection - 모바일 데이터 종량제 사용 시 대용량 데이터 업로드 방지 - - - default - 기본 - - - metered - 종량제 - - - unmetered - 무제한 - - - Wi-Fi Network Metered - 제한된 Wi-Fi 네트워크 - - - Prevent large data uploads when on a metered Wi-Fi connection - 제한된 Wi-Fi 사용 시 대용량 데이터 업로드 방지 - - - - ConfirmationDialog - - Ok - 확인 - - - Cancel - 취소 - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - 오픈파일럿을 사용하려면 이용약관에 동의해야 합니다. - - - Back - 뒤로 - - - Decline, uninstall %1 - 거절, %1 제거 - - - - DeveloperPanel - - Joystick Debug Mode - 조이스틱 디버그 모드 - - - Longitudinal Maneuver Mode - 가감속 제어 조작 모드 - - - openpilot Longitudinal Control (Alpha) - 오픈파일럿 가감속 제어 (알파) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - 경고: 오픈파일럿 가감속 제어는 알파 기능으로 차량의 자동긴급제동(AEB)기능이 작동하지 않습니다. - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - 이 차량에서 오픈파일럿은 오픈파일럿 가감속 제어 대신 기본적으로 차량의 ACC로 가감속을 제어합니다. 오픈파일럿 가감속 제어로 전환하려면 이 기능을 활성화하세요. 오픈파일럿 가감속 제어 알파 기능을 활성화하는 경우 실험 모드 활성화를 권장합니다. - - - Enable ADB - ADB 사용 - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB (안드로이드 디버그 브릿지) USB 또는 네트워크를 통해 장치에 연결할 수 있습니다. 자세한 내용은 https://docs.comma.ai/how-to/connect-to-comma를 참조하세요. - - - - DevicePanel - - Dongle ID - 동글 ID - - - N/A - N/A - - - Serial - 시리얼 - - - Driver Camera - 운전자 카메라 - - - PREVIEW - 미리보기 - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - 운전자 모니터링이 잘 되는지 확인하기 위해 후면 카메라를 미리 봅니다. (차량 시동이 꺼져 있어야 합니다) - - - Reset Calibration - 캘리브레이션 - - - RESET - 초기화 - - - Are you sure you want to reset calibration? - 캘리브레이션을 초기화하시겠습니까? - - - Review Training Guide - 트레이닝 가이드 - - - REVIEW - 다시보기 - - - Review the rules, features, and limitations of openpilot - 오픈파일럿의 규칙, 기능 및 제한 다시 확인 - - - Are you sure you want to review the training guide? - 트레이닝 가이드를 다시 확인하시겠습니까? - - - Regulatory - 규제 - - - VIEW - 보기 - - - Change Language - 언어 변경 - - - CHANGE - 변경 - - - Select a language - 언어를 선택하세요 - - - Reboot - 재부팅 - - - Power Off - 전원 끄기 - - - Your device is pointed %1° %2 and %3° %4. - 사용자의 장치는 %2 %1° 및 %4 %3° 의 방향으로 장착되어 있습니다. - - - down - 아래로 - - - up - 위로 - - - left - 좌측으로 - - - right - 우측으로 - - - Are you sure you want to reboot? - 재부팅하시겠습니까? - - - Disengage to Reboot - 재부팅하려면 연결을 해제하세요 - - - Are you sure you want to power off? - 전원을 끄시겠습니까? - - - Disengage to Power Off - 전원을 끄려면 연결을 해제하세요 - - - Reset - 초기화 - - - Review - 다시보기 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 장치를 comma connect (connect.comma.ai)에서 동기화하고 comma prime 무료 이용권을 사용하세요. - - - Pair Device - 장치 동기화 - - - PAIR - 동기화 - - - Disengage to Reset Calibration - 캘리브레이션을 재설정하려면 해제하세요 - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - 오픈파일럿 장치는 좌우측으로는 4° 또는 위로는 5° 아래로는 9° 이내에 장착해야합니다. - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - 오픈파일럿은 지속적으로 갤리브레이션되어 재설정이 거의 필요하지 않습니다. 차량과 연결된 경우 캘리브레이션 재설정이 오픈파일럿을 재시작합니다. - - - - -Steering lag calibration is %1% complete. - - -조향 지연 캘리브레이션이 %1% 진행되었습니다. - - - - -Steering lag calibration is complete. - - -조향 지연 캘리브레이션이 완료되었습니다. - - - Steering torque response calibration is %1% complete. - 조향 토크 응답 캘리브레이션이 %1% 진행되었습니다. - - - Steering torque response calibration is complete. - 조향 토크 응답 캘리브레이션이 완료되었습니다. - - - - DriverViewWindow - - camera starting - 카메라 시작 중 - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - 실험 모드 사용 - - - CHILL MODE ON - 안정 모드 사용 - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - 오픈파일럿은 여러분과 같은 사람이 운전하는 모습을 보면서 운전하는 법을 배웁니다. - -파이어호스 모드를 사용하면 학습 데이터 업로드를 최대화하여 오픈파일럿의 주행 모델을 개선할 수 있습니다. 더 많은 데이터는 더 큰 모델을 의미하며, 이는 더 나은 실험 모드를 의미합니다. - - - Firehose Mode: ACTIVE - 파이어호스 모드: 활성화 - - - ACTIVE - 활성 상태 - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - 최대한의 효과를 얻으려면 매주 장치를 실내로 가져와 좋은 USB-C 충전기와 Wi-Fi에 연결하세요.<br><br>파이어호스 모드는 핫스팟 또는 무제한 네트워크에 연결된 경우 주행 중에도 작동할 수 있습니다.<br><br><br><b>자주 묻는 질문</b><br><br><i>운전 방법이나 장소가 중요한가요?</i> 아니요, 평소처럼 운전하시면 됩니다.<br><br><i>파이어호스 모드에서 제 모든 구간을 가져오나요?<br><br><i> 아니요, 저희는 여러분의 구간 중 일부를 선별적으로 가져옵니다.<br><br><i>좋은 USB-C 충전기는 무엇인가요?</i> 휴대폰이나 노트북충전이 가능한 고속 충전기이면 괜찮습니다.<br><br><i>어떤 소프트웨어를 실행하는지가 중요한가요?</i> 예, 오직 공식 오픈파일럿의 특정 포크만 트레이닝에 사용할 수 있습니다. - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>%n 구간</b> 의 운전이 지금까지의 학습 데이터셋에 포함되어 있습니다. - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>비활성 상태</span>: 무제한 네트워크에 연결 하세요 - - - Firehose Mode - 파이어호스 모드 - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - MAX - - - - InputDialog - - Cancel - 취소 - - - Need at least %n character(s)! - - 최소 %n자 이상이어야 합니다! - - - - - MultiOptionDialog - - Select - 선택 - - - Cancel - 취소 - - - - Networking - - Advanced - 고급 설정 - - - Enter password - 비밀번호를 입력하세요 - - - for "%1" - "%1"에 접속하려면 비밀번호가 필요합니다 - - - Wrong password - 비밀번호가 틀렸습니다 - - - - OffroadAlert - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - 즉시 인터넷에 연결하여 업데이트를 확인하세요. 인터넷에 연결되어 있지 않으면 %1 이후에는 오픈파일럿이 활성화되지 않습니다. - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - 업데이트 확인을 위해 인터넷 연결이 필요합니다. 오픈파일럿은 업데이트 확인을 위해 인터넷에 연결될 때까지 자동으로 시작되지 않습니다. - - - Unable to download updates -%1 - 업데이트를 다운로드할 수 없습니다 -%1 - - - Taking camera snapshots. System won't start until finished. - 카메라 스냅샷 찍기가 완료될 때까지 시스템이 시작되지 않습니다. - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - 백그라운드에서 운영 체제에 대한 업데이트가 다운로드되고 있습니다. 설치가 준비되면 업데이트 메시지가 표시됩니다. - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - 오픈파일럿이 차량을 식별할 수 없습니다. 지원되지 않는 차량이거나 ECU가 인식되지 않습니다. 해당 차량에 맞는 펌웨어 버전을 추가하려면 PR을 제출하세요. 도움이 필요하시면 discord.comma.ai에 참여하세요. - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - 오픈파일럿 장치의 장착 위치가 변경되었습니다. 장치가 마운트에 완전히 장착되고 마운트가 앞유리에 단단히 고정되었는지 확인하세요. - - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - 장치 온도가 너무 높습니다. 시작하기 전에 시스템을 냉각하고 있습니다. 현재 내부 구성 요소 온도: %1 - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - 장치를 comma.ai 백엔드에 등록하지 못했습니다. comma.ai 서버에 연결하거나 업로드하지 않으며 comma.ai로부터 지원을받지 않습니다. comma.ai shop에서 구매 한 장치 인 경우 https://comma.ai/support에서 티켓을 여십시오. - - - Acknowledge Excessive Actuation - 과도한 작동을 인정하십시오 - - - Snooze Update - 업데이트 일시 중지 - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - 업데이트 - - - ALERTS - 알림 - - - ALERT - 알림 - - - - OnroadAlerts - - openpilot Unavailable - 오픈파일럿을 사용할수없습니다 - - - TAKE CONTROL IMMEDIATELY - 핸들을 잡아주세요 - - - Reboot Device - 장치를 재부팅하세요 - - - Waiting to start - 시작을 기다리는중 - - - System Unresponsive - 시스템이 응답하지않습니다 - - - - PairingPopup - - Pair your device to your comma account - 장치를 comma 계정에 동기화합니다 - - - Go to https://connect.comma.ai on your phone - https://connect.comma.ai에 접속하세요 - - - Click "add new device" and scan the QR code on the right - "새 장치 추가"를 클릭하고 오른쪽 QR 코드를 스캔하세요 - - - Bookmark connect.comma.ai to your home screen to use it like an app - connect.comma.ai를 앱처럼 사용하려면 홈 화면에 바로가기를 만드세요 - - - Please connect to Wi-Fi to complete initial pairing - 초기 동기화를 완료하려면 Wi-Fi에 연결하세요. - - - - ParamControl - - Cancel - 취소 - - - Enable - 활성화 - - - - PrimeAdWidget - - Upgrade Now - 지금 업그레이드하세요 - - - Become a comma prime member at connect.comma.ai - connect.comma.ai에서 comma prime 사용자로 등록하세요 - - - PRIME FEATURES: - PRIME 기능: - - - Remote access - 원격 접속 - - - 24/7 LTE connectivity - 항상 LTE 연결 - - - 1 year of drive storage - 1년간 주행 로그 저장 - - - Remote snapshots - 원격 스냅샷 - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ 구독함 - - - comma prime - comma prime - - - - QObject - - openpilot - 오픈파일럿 - - - %n minute(s) ago - - %n 분 전 - - - - %n hour(s) ago - - %n 시간 전 - - - - %n day(s) ago - - %n 일 전 - - - - now - now - - - - SettingsWindow - - × - × - - - Device - 장치 - - - Network - 네트워크 - - - Toggles - 토글 - - - Software - 소프트웨어 - - - Developer - 개발자 - - - Firehose - 파이어호스 - - - - SetupWidget - - Finish Setup - 설정 완료 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 장치를 comma connect (connect.comma.ai)에서 동기화하고 comma prime 무료 이용권을 사용하세요. - - - Pair device - 장치 동기화 - - - - Sidebar - - CONNECT - 커넥트 - - - OFFLINE - 연결 안됨 - - - ONLINE - 온라인 - - - ERROR - 오류 - - - TEMP - 온도 - - - HIGH - 높음 - - - GOOD - 좋음 - - - OK - OK - - - VEHICLE - 차량 - - - NO - NO - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - LAN - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - 업데이트는 차량 시동이 꺼졌을 때 다운로드됩니다. - - - Current Version - 현재 버전 - - - Download - 다운로드 - - - Install Update - 업데이트 설치 - - - INSTALL - 설치 - - - Target Branch - 대상 브랜치 - - - SELECT - 선택 - - - Select a branch - 브랜치 선택 - - - UNINSTALL - 제거 - - - Uninstall %1 - %1 제거 - - - Are you sure you want to uninstall? - 제거하시겠습니까? - - - CHECK - 확인 - - - Uninstall - 제거 - - - failed to check for update - 업데이트를 확인하지 못했습니다 - - - up to date, last checked %1 - 최신 버전입니다. 마지막 확인: %1 - - - DOWNLOAD - 다운로드 - - - update available - 업데이트 가능 - - - never - 업데이트 안함 - - - - SshControl - - SSH Keys - SSH 키 - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - 경고: 이 설정은 GitHub에 등록된 모든 공용 키에 대해 SSH 액세스 권한을 부여합니다. 본인의 GitHub 사용자 아이디 이외에는 입력하지 마십시오. comma에서는 GitHub 아이디를 추가하라는 요청을 하지 않습니다. - - - ADD - 추가 - - - Enter your GitHub username - GitHub 사용자 ID - - - LOADING - 로딩 중 - - - REMOVE - 삭제 - - - Username '%1' has no keys on GitHub - 사용자 '%1'의 GitHub에 키가 등록되어 있지 않습니다 - - - Request timed out - 요청 시간 초과 - - - Username '%1' doesn't exist on GitHub - GitHub 사용자 '%1'를 찾지 못했습니다 - - - - SshToggle - - Enable SSH - SSH 사용 - - - - TermsPage - - Decline - 거절 - - - Agree - 동의 - - - Welcome to openpilot - 오픈파일럿에 오신 것을 환영합니다. - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - 오픈파일럿을 사용하려면 이용약관에 동의해야 합니다. 최신 약관은 <span style='color: #465BEA;'>https://comma.ai/terms</span> 에서 최신 약관을 읽은 후 계속하세요. - - - - TogglesPanel - - Enable openpilot - 오픈파일럿 사용 - - - Enable Lane Departure Warnings - 차선 이탈 경고 활성화 - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - 차량이 50km/h(31mph) 이상의 속도로 주행할 때 방향지시등이 켜지지 않은 상태에서 차선을 벗어나면 경고합니다. - - - Use Metric System - 미터법 사용 - - - Display speed in km/h instead of mph. - mph 대신 km/h로 속도를 표시합니다. - - - Record and Upload Driver Camera - 운전자 카메라 녹화 및 업로드 - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - 운전자 카메라의 영상 데이터를 업로드하여 운전자 모니터링 알고리즘을 개선합니다. - - - Disengage on Accelerator Pedal - 가속페달 조작 시 해제 - - - When enabled, pressing the accelerator pedal will disengage openpilot. - 활성화된 경우 가속 페달을 밟으면 오픈파일럿이 해제됩니다. - - - Experimental Mode - 실험 모드 - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - 오픈파일럿은 기본적으로 <b>안정 모드</b>로 주행합니다. 실험 모드는 안정화되지 않은 <b>알파 수준의 기능</b>을 활성화합니다. 실험 모드의 기능은 아래와 같습니다: - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - 주행모델이 가감속을 제어하도록 합니다. 오픈파일럿은 빨간불과 정지신호를 보고 정지하는것을 포함하여 사람이 운전하는 방식대로 작동하며 주행 모델이 속도를 결정하므로 설정 속도는 최대 제한 속도로만 작동합니다. 이는 알파 수준의 기능이며 오류가 발생할수있으니 사용에 주의해야 합니다. - - - New Driving Visualization - 새로운 주행 시각화 - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - 차량의 ACC가 가감속 제어에 사용되기 때문에, 이 차량에서는 실험 모드를 사용할 수 없습니다. - - - openpilot longitudinal control may come in a future update. - 오픈파일럿 가감속 제어는 향후 업데이트에서 지원될 수 있습니다. - - - Aggressive - 공격적 - - - Standard - 표준 - - - Relaxed - 편안한 - - - Driving Personality - 주행 모드 - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 오픈파일럿 가감속 제어 알파 버전은 비 릴리즈 브랜치에서 실험 모드와 함께 테스트할 수 있습니다. - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - 실험 모드를 사용하려면 오픈파일럿 E2E 가감속 제어 (알파) 토글을 활성화하세요. - - - End-to-End Longitudinal Control - E2E 가감속 제어 - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 표준 모드를 권장합니다. 공격적 모드의 오픈파일럿은 선두 차량을 더 가까이 따라가고 가감속제어를 사용하여 더욱 공격적으로 움직입니다. 편안한 모드의 오픈파일럿은 선두 차량으로부터 더 멀리 떨어져 있습니다. 지원되는 차량에서는 차간거리 버튼을 사용하여 이러한 특성을 순환할 수 있습니다. - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - 운전 시각화는 일부 회전을 더 잘 보여주기 위해 저속에서 도로를 향한 광각 카메라로 전환됩니다. 우측 상단에 실험 모드 로고가 표시됩니다. - - - Always-On Driver Monitoring - 상시 운전자 모니터링 - - - Enable driver monitoring even when openpilot is not engaged. - 오픈파일럿이 활성화되지 않은 경우에도 드라이버 모니터링을 활성화합니다. - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - ACC 및 차선 유지 지원을 위해 오픈파일럿 시스템을 사용하십시오. 이 기능을 사용하려면 항상주의를 기울여야합니다. - - - Changing this setting will restart openpilot if the car is powered on. - 이 설정을 변경하면 차량이 재가동된후 오픈파일럿이 시작됩니다. - - - Record and Upload Microphone Audio - 마이크 오디오 녹음 및 업로드 - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - 운전 중에 마이크 오디오를 녹음하고 저장하십시오. 오디오는 comma connect의 대시캠 비디오에 포함됩니다. - - - - WiFiPromptWidget - - Open - 열기 - - - Maximize your training data uploads to improve openpilot's driving models. - 오픈파일럿의 주행 모델 개선을 위해 학습 데이터 업로드를 최대화하세요. - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> 파이어호스 모드 <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - 네트워크 검색 중... - - - CONNECTING... - 연결 중... - - - FORGET - 삭제 - - - Forget Wi-Fi Network "%1"? - Wi-Fi "%1"에 자동으로 연결하지 않겠습니까? - - - Forget - 삭제 - - - diff --git a/selfdrive/ui/translations/nl.ts b/selfdrive/ui/translations/nl.ts deleted file mode 100644 index 10651a4160..0000000000 --- a/selfdrive/ui/translations/nl.ts +++ /dev/null @@ -1,1120 +0,0 @@ - - - - - AbstractAlert - - Close - Sluit - - - Snooze Update - Update uitstellen - - - Reboot and Update - Opnieuw Opstarten en Updaten - - - - AdvancedNetworking - - Back - Terug - - - Enable Tethering - Tethering Inschakelen - - - Tethering Password - Tethering Wachtwoord - - - EDIT - AANPASSEN - - - Enter new tethering password - Voer nieuw tethering wachtwoord in - - - IP Address - IP Adres - - - Enable Roaming - Roaming Inschakelen - - - APN Setting - APN Instelling - - - Enter APN - Voer APN in - - - leave blank for automatic configuration - laat leeg voor automatische configuratie - - - Cellular Metered - - - - Prevent large data uploads when on a metered connection - - - - - AnnotatedCameraWidget - - km/h - km/u - - - mph - mph - - - MAX - MAX - - - SPEED - SPEED - - - LIMIT - LIMIT - - - - ConfirmationDialog - - Ok - Ok - - - Cancel - Annuleren - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - U moet de Algemene Voorwaarden accepteren om openpilot te gebruiken. - - - Back - Terug - - - Decline, uninstall %1 - Afwijzen, verwijder %1 - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - Nvt - - - Serial - Serienummer - - - Driver Camera - Bestuurders Camera - - - PREVIEW - BEKIJKEN - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Bekijk de naar de bestuurder gerichte camera om ervoor te zorgen dat het monitoren van de bestuurder goed zicht heeft. (Voertuig moet uitgschakeld zijn) - - - Reset Calibration - Kalibratie Resetten - - - RESET - RESET - - - Are you sure you want to reset calibration? - Weet u zeker dat u de kalibratie wilt resetten? - - - Review Training Guide - Doorloop de Training Opnieuw - - - REVIEW - BEKIJKEN - - - Review the rules, features, and limitations of openpilot - Bekijk de regels, functies en beperkingen van openpilot - - - Are you sure you want to review the training guide? - Weet u zeker dat u de training opnieuw wilt doorlopen? - - - Regulatory - Regelgeving - - - VIEW - BEKIJKEN - - - Change Language - Taal Wijzigen - - - CHANGE - WIJZIGEN - - - Select a language - Selecteer een taal - - - Reboot - Opnieuw Opstarten - - - Power Off - Uitschakelen - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot vereist dat het apparaat binnen 4° links of rechts en binnen 5° omhoog of 8° omlaag wordt gemonteerd. openpilot kalibreert continu, resetten is zelden nodig. - - - Your device is pointed %1° %2 and %3° %4. - Uw apparaat is gericht op %1° %2 en %3° %4. - - - down - omlaag - - - up - omhoog - - - left - links - - - right - rechts - - - Are you sure you want to reboot? - Weet u zeker dat u opnieuw wilt opstarten? - - - Disengage to Reboot - Deactiveer openpilot om opnieuw op te starten - - - Are you sure you want to power off? - Weet u zeker dat u wilt uitschakelen? - - - Disengage to Power Off - Deactiveer openpilot om uit te schakelen - - - - DriveStats - - Drives - Ritten - - - Hours - Uren - - - ALL TIME - TOTAAL - - - PAST WEEK - AFGELOPEN WEEK - - - KM - Km - - - Miles - Mijl - - - - DriverViewScene - - camera starting - Camera wordt gestart - - - - InputDialog - - Cancel - Annuleren - - - Need at least %n character(s)! - - Heeft minstens %n karakter nodig! - Heeft minstens %n karakters nodig! - - - - - Installer - - Installing... - Installeren... - - - Receiving objects: - Objecten ontvangen: - - - Resolving deltas: - Deltas verwerken: - - - Updating files: - Bestanden bijwerken: - - - - MapETA - - eta - eta - - - min - min - - - hr - uur - - - km - km - - - mi - mi - - - - MapInstructions - - km - km - - - m - m - - - mi - mi - - - ft - ft - - - - MapPanel - - Current Destination - Huidige Bestemming - - - CLEAR - LEEGMAKEN - - - Recent Destinations - Recente Bestemmingen - - - Try the Navigation Beta - Probeer de Navigatie Bèta - - - Get turn-by-turn directions displayed and more with a comma -prime subscription. Sign up now: https://connect.comma.ai - Krijg stapsgewijze routebeschrijving en meer met een comma -prime abonnement. Meld u nu aan: https://connect.comma.ai - - - No home -location set - Geen thuislocatie -ingesteld - - - No work -location set - Geen werklocatie -ingesteld - - - no recent destinations - geen recente bestemmingen - - - - MapWindow - - Map Loading - Kaart wordt geladen - - - Waiting for GPS - Wachten op GPS - - - - MultiOptionDialog - - Select - Selecteer - - - Cancel - Annuleren - - - - Networking - - Advanced - Geavanceerd - - - Enter password - Voer wachtwoord in - - - for "%1" - voor "%1" - - - Wrong password - Verkeerd wachtwoord - - - - OffroadHome - - UPDATE - UPDATE - - - ALERTS - WAARSCHUWINGEN - - - ALERT - WAARSCHUWING - - - - PairingPopup - - Pair your device to your comma account - Koppel uw apparaat aan uw comma-account - - - Go to https://connect.comma.ai on your phone - Ga naar https://connect.comma.ai op uw telefoon - - - Click "add new device" and scan the QR code on the right - Klik op "add new device" en scan de QR-code aan de rechterkant - - - Bookmark connect.comma.ai to your home screen to use it like an app - Voeg connect.comma.ai toe op uw startscherm om het als een app te gebruiken - - - - PrimeAdWidget - - Upgrade Now - Upgrade nu - - - Become a comma prime member at connect.comma.ai - Word een comma prime lid op connect.comma.ai - - - PRIME FEATURES: - PRIME BEVAT: - - - Remote access - Toegang op afstand - - - 1 year of storage - 1 jaar lang opslag - - - Developer perks - Voordelen voor ontwikkelaars - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ GEABONNEERD - - - comma prime - comma prime - - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - - - COMMA POINTS - COMMA PUNTEN - - - - QObject - - Reboot - Opnieuw Opstarten - - - Exit - Afsluiten - - - dashcam - dashcam - - - openpilot - openpilot - - - %n minute(s) ago - - %n minuut geleden - %n minuten geleden - - - - %n hour(s) ago - - %n uur geleden - %n uur geleden - - - - %n day(s) ago - - %n dag geleden - %n dagen geleden - - - - - Reset - - Reset failed. Reboot to try again. - Opnieuw instellen mislukt. Start opnieuw op om opnieuw te proberen. - - - Are you sure you want to reset your device? - Weet u zeker dat u uw apparaat opnieuw wilt instellen? - - - Resetting device... - Apparaat opnieuw instellen... - - - System Reset - Systeemreset - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Systeemreset geactiveerd. Druk op bevestigen om alle inhoud en instellingen te wissen. Druk op Annuleren om het opstarten te hervatten. - - - Cancel - Annuleren - - - Reboot - Opnieuw Opstarten - - - Confirm - Bevestigen - - - Unable to mount data partition. Press confirm to reset your device. - Kan gegevenspartitie niet koppelen. Druk op bevestigen om uw apparaat te resetten. - - - - RichTextDialog - - Ok - Ok - - - - SettingsWindow - - × - × - - - Device - Apparaat - - - Network - Netwerk - - - Toggles - Opties - - - Software - Software - - - Navigation - Navigatie - - - - Setup - - WARNING: Low Voltage - WAARCHUWING: Lage Spanning - - - Power your device in a car with a harness or proceed at your own risk. - Voorzie uw apparaat van stroom in een auto met een harnas (car harness) of ga op eigen risico verder. - - - Power off - Uitschakelen - - - Continue - Doorgaan - - - Getting Started - Aan de slag - - - Before we get on the road, let’s finish installation and cover some details. - Laten we, voordat we op pad gaan, de installatie afronden en enkele details bespreken. - - - Connect to Wi-Fi - Maak verbinding met Wi-Fi - - - Back - Terug - - - Continue without Wi-Fi - Doorgaan zonder Wi-Fi - - - Waiting for internet - Wachten op internet - - - Choose Software to Install - Kies Software om te Installeren - - - Dashcam - Dashcam - - - Custom Software - Andere Software - - - Enter URL - Voer URL in - - - for Custom Software - voor Andere Software - - - Downloading... - Downloaden... - - - Download Failed - Downloaden Mislukt - - - Ensure the entered URL is valid, and the device’s internet connection is good. - Zorg ervoor dat de ingevoerde URL geldig is en dat de internetverbinding van het apparaat goed is. - - - Reboot device - Apparaat opnieuw opstarten - - - Start over - Begin opnieuw - - - - SetupWidget - - Finish Setup - Installatie voltooien - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Koppel uw apparaat met comma connect (connect.comma.ai) en claim uw comma prime-aanbieding. - - - Pair device - Apparaat koppelen - - - - Sidebar - - CONNECT - VERBINDING - - - OFFLINE - OFFLINE - - - ONLINE - ONLINE - - - ERROR - FOUT - - - TEMP - TEMP - - - HIGH - HOOG - - - GOOD - GOED - - - OK - OK - - - VEHICLE - VOERTUIG - - - NO - GEEN - - - PANDA - PANDA - - - GPS - GPS - - - SEARCH - ZOEKEN - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - 4G - - - 5G - 5G - - - - SoftwarePanel - - Git Branch - Git Branch - - - Git Commit - Git Commit - - - OS Version - OS Versie - - - Version - Versie - - - Last Update Check - Laatste Updatecontrole - - - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - De laatste keer dat openpilot met succes heeft gecontroleerd op een update. De updater werkt alleen als de auto is uitgeschakeld. - - - Check for Update - Controleer op Updates - - - CHECKING - CONTROLEER - - - Switch Branch - Branch Verwisselen - - - ENTER - INVOEREN - - - The new branch will be pulled the next time the updater runs. - Tijdens de volgende update wordt de nieuwe branch opgehaald. - - - Enter branch name - Voer branch naam in - - - Uninstall %1 - Verwijder %1 - - - UNINSTALL - VERWIJDER - - - Are you sure you want to uninstall? - Weet u zeker dat u de installatie ongedaan wilt maken? - - - failed to fetch update - ophalen van update mislukt - - - CHECK - CONTROLEER - - - Updates are only downloaded while the car is off. - - - - Current Version - - - - Download - - - - Install Update - - - - INSTALL - - - - Target Branch - - - - SELECT - - - - Select a branch - - - - - SshControl - - SSH Keys - SSH Sleutels - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Waarschuwing: dit geeft SSH toegang tot alle openbare sleutels in uw GitHub-instellingen. Voer nooit een andere GitHub-gebruikersnaam in dan die van uzelf. Een medewerker van comma zal u NOOIT vragen om zijn GitHub-gebruikersnaam toe te voegen. - - - ADD - TOEVOEGEN - - - Enter your GitHub username - Voer uw GitHub gebruikersnaam in - - - LOADING - LADEN - - - REMOVE - VERWIJDEREN - - - Username '%1' has no keys on GitHub - Gebruikersnaam '%1' heeft geen SSH sleutels op GitHub - - - Request timed out - Time-out van aanvraag - - - Username '%1' doesn't exist on GitHub - Gebruikersnaam '%1' bestaat niet op GitHub - - - - SshToggle - - Enable SSH - SSH Inschakelen - - - - TermsPage - - Terms & Conditions - Algemene Voorwaarden - - - Decline - Afwijzen - - - Scroll to accept - Scroll om te accepteren - - - Agree - Akkoord - - - - TogglesPanel - - Enable openpilot - openpilot Inschakelen - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Gebruik het openpilot-systeem voor adaptieve cruisecontrol en rijstrookassistentie. Uw aandacht is te allen tijde vereist om deze functie te gebruiken. Het wijzigen van deze instelling wordt van kracht wanneer de auto wordt uitgeschakeld. - - - Enable Lane Departure Warnings - Waarschuwingen bij Verlaten Rijstrook Inschakelen - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Ontvang waarschuwingen om terug naar de rijstrook te sturen wanneer uw voertuig over een gedetecteerde rijstrookstreep drijft zonder dat de richtingaanwijzer wordt geactiveerd terwijl u harder rijdt dan 50 km/u (31 mph). - - - Use Metric System - Gebruik Metrisch Systeem - - - Display speed in km/h instead of mph. - Geef snelheid weer in km/u in plaats van mph. - - - Record and Upload Driver Camera - Opnemen en Uploaden van de Bestuurders Camera - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Upload gegevens van de bestuurders camera en help het algoritme voor het monitoren van de bestuurder te verbeteren. - - - Disengage on Accelerator Pedal - Deactiveren Met Gaspedaal - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Indien ingeschakeld, zal het indrukken van het gaspedaal openpilot deactiveren. - - - Show ETA in 24h Format - Toon verwachte aankomsttijd in 24-uurs formaat - - - Use 24h format instead of am/pm - Gebruik 24-uurs formaat in plaats van AM en PM - - - Show Map on Left Side of UI - Toon kaart aan linkerkant van het scherm - - - Show map on left side when in split screen view. - Toon kaart links in gesplitste schermweergave. - - - openpilot Longitudinal Control - openpilot Longitudinale Controle - - - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - openpilot zal de radar van de auto uitschakelen en de controle over gas en remmen overnemen. Waarschuwing: hierdoor wordt AEB (automatische noodrem) uitgeschakeld! - - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - - - - Experimental openpilot Longitudinal Control - - - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - - - - openpilot longitudinal control is not currently available for this car. - - - - Enable experimental longitudinal control to enable this. - - - - - Updater - - Update Required - Update Vereist - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Een update van het besturingssysteem is vereist. Verbind je apparaat met Wi-Fi voor de snelste update-ervaring. De downloadgrootte is ongeveer 1 GB. - - - Connect to Wi-Fi - Maak verbinding met Wi-Fi - - - Install - Installeer - - - Back - Terug - - - Loading... - Aan het laden... - - - Reboot - Opnieuw Opstarten - - - Update failed - Update mislukt - - - - WifiUI - - Scanning for networks... - Scannen naar netwerken... - - - CONNECTING... - VERBINDEN... - - - FORGET - VERGETEN - - - Forget Wi-Fi Network "%1"? - Vergeet Wi-Fi Netwerk "%1"? - - - diff --git a/selfdrive/ui/translations/pl.ts b/selfdrive/ui/translations/pl.ts deleted file mode 100644 index 4f8b03ef50..0000000000 --- a/selfdrive/ui/translations/pl.ts +++ /dev/null @@ -1,1124 +0,0 @@ - - - - - AbstractAlert - - Close - Zamknij - - - Snooze Update - Zaktualizuj później - - - Reboot and Update - Uruchom ponownie i zaktualizuj - - - - AdvancedNetworking - - Back - Wróć - - - Enable Tethering - Włącz hotspot osobisty - - - Tethering Password - Hasło do hotspotu - - - EDIT - EDYTUJ - - - Enter new tethering password - Wprowadź nowe hasło do hotspotu - - - IP Address - Adres IP - - - Enable Roaming - Włącz roaming danych - - - APN Setting - Ustawienia APN - - - Enter APN - Wprowadź APN - - - leave blank for automatic configuration - Pozostaw puste, aby użyć domyślnej konfiguracji - - - Cellular Metered - - - - Prevent large data uploads when on a metered connection - - - - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - MAX - - - SPEED - PRĘDKOŚĆ - - - LIMIT - OGRANICZENIE - - - - ConfirmationDialog - - Ok - Ok - - - Cancel - Anuluj - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - Aby korzystać z openpilota musisz zaakceptować regulamin. - - - Back - Wróć - - - Decline, uninstall %1 - Odrzuć, odinstaluj %1 - - - - DevicePanel - - Dongle ID - ID adaptera - - - N/A - N/A - - - Serial - Numer seryjny - - - Driver Camera - Kamera kierowcy - - - PREVIEW - PODGLĄD - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Wyświetl podgląd z kamery skierowanej na kierowcę, aby upewnić się, że monitoring kierowcy ma dobry zakres widzenia. (pojazd musi być wyłączony) - - - Reset Calibration - Zresetuj kalibrację - - - RESET - ZRESETUJ - - - Are you sure you want to reset calibration? - Czy na pewno chcesz zresetować kalibrację? - - - Review Training Guide - Zapoznaj się z samouczkiem - - - REVIEW - ZAPOZNAJ SIĘ - - - Review the rules, features, and limitations of openpilot - Zapoznaj się z zasadami, funkcjami i ograniczeniami openpilota - - - Are you sure you want to review the training guide? - Czy na pewno chcesz się zapoznać z samouczkiem? - - - Regulatory - Regulacja - - - VIEW - WIDOK - - - Change Language - Zmień język - - - CHANGE - ZMIEŃ - - - Select a language - Wybierz język - - - Reboot - Uruchom ponownie - - - Power Off - Wyłącz - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot wymaga, aby urządzenie było zamontowane z maksymalnym odchyłem 4° poziomo, 5° w górę oraz 8° w dół. openpilot jest ciągle kalibrowany, rzadko konieczne jest resetowania urządzenia. - - - Your device is pointed %1° %2 and %3° %4. - Twoje urządzenie jest skierowane %1° %2 oraz %3° %4. - - - down - w dół - - - up - w górę - - - left - w lewo - - - right - w prawo - - - Are you sure you want to reboot? - Czy na pewno chcesz uruchomić ponownie urządzenie? - - - Disengage to Reboot - Aby uruchomić ponownie, odłącz sterowanie - - - Are you sure you want to power off? - Czy na pewno chcesz wyłączyć urządzenie? - - - Disengage to Power Off - Aby wyłączyć urządzenie, odłącz sterowanie - - - - DriveStats - - Drives - Przejazdy - - - Hours - Godziny - - - ALL TIME - CAŁKOWICIE - - - PAST WEEK - OSTATNI TYDZIEŃ - - - KM - KM - - - Miles - Mile - - - - DriverViewScene - - camera starting - uruchamianie kamery - - - - InputDialog - - Cancel - Anuluj - - - Need at least %n character(s)! - - Wpisana wartość powinna składać się przynajmniej z %n znaku! - Wpisana wartość powinna skłądać się przynajmniej z %n znaków! - Wpisana wartość powinna skłądać się przynajmniej z %n znaków! - - - - - Installer - - Installing... - Instalowanie... - - - Receiving objects: - Odbieranie obiektów: - - - Resolving deltas: - Rozwiązywanie różnic: - - - Updating files: - Aktualizacja plików: - - - - MapETA - - eta - przewidywany czas - - - min - min - - - hr - godz - - - km - km - - - mi - mi - - - - MapInstructions - - km - km - - - m - m - - - mi - mi - - - ft - ft - - - - MapPanel - - Current Destination - Miejsce docelowe - - - CLEAR - WYCZYŚĆ - - - Recent Destinations - Ostatnie miejsca docelowe - - - Try the Navigation Beta - Wypróbuj nawigację w wersji beta - - - Get turn-by-turn directions displayed and more with a comma -prime subscription. Sign up now: https://connect.comma.ai - Odblokuj nawigację zakręt po zakęcie i wiele więcej subskrybując -comma prime. Zarejestruj się teraz: https://connect.comma.ai - - - No home -location set - Lokalizacja domu -nie została ustawiona - - - No work -location set - Miejsce pracy -nie zostało ustawione - - - no recent destinations - brak ostatnich miejsc docelowych - - - - MapWindow - - Map Loading - Ładowanie Mapy - - - Waiting for GPS - Oczekiwanie na sygnał GPS - - - - MultiOptionDialog - - Select - Wybierz - - - Cancel - Anuluj - - - - Networking - - Advanced - Zaawansowane - - - Enter password - Wprowadź hasło - - - for "%1" - do "%1" - - - Wrong password - Niepoprawne hasło - - - - OffroadHome - - UPDATE - UAKTUALNIJ - - - ALERTS - ALERTY - - - ALERT - ALERT - - - - PairingPopup - - Pair your device to your comma account - Sparuj swoje urzadzenie ze swoim kontem comma - - - Go to https://connect.comma.ai on your phone - Wejdź na stronę https://connect.comma.ai na swoim telefonie - - - Click "add new device" and scan the QR code on the right - Kliknij "add new device" i zeskanuj kod QR znajdujący się po prawej stronie - - - Bookmark connect.comma.ai to your home screen to use it like an app - Dodaj connect.comma.ai do zakładek na swoim ekranie początkowym, aby korzystać z niej jak z aplikacji - - - - PrimeAdWidget - - Upgrade Now - Uaktualnij teraz - - - Become a comma prime member at connect.comma.ai - Zostań członkiem comma prime na connect.comma.ai - - - PRIME FEATURES: - FUNKCJE PRIME: - - - Remote access - Zdalny dostęp - - - 1 year of storage - 1 rok przechowywania danych - - - Developer perks - Udogodnienia dla programistów - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ ZASUBSKRYBOWANO - - - comma prime - comma prime - - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - - - COMMA POINTS - COMMA POINTS - - - - QObject - - Reboot - Uruchom Ponownie - - - Exit - Wyjdź - - - dashcam - wideorejestrator - - - openpilot - openpilot - - - %n minute(s) ago - - %n minutę temu - %n minuty temu - %n minut temu - - - - %n hour(s) ago - - % godzinę temu - %n godziny temu - %n godzin temu - - - - %n day(s) ago - - %n dzień temu - %n dni temu - %n dni temu - - - - - Reset - - Reset failed. Reboot to try again. - Wymazywanie zakończone niepowodzeniem. Aby spróbować ponownie, uruchom ponownie urządzenie. - - - Are you sure you want to reset your device? - Czy na pewno chcesz wymazać urządzenie? - - - Resetting device... - Wymazywanie urządzenia... - - - System Reset - Przywróć do ustawień fabrycznych - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Przywracanie do ustawień fabrycznych. Wciśnij potwierdź, aby usunąć wszystkie dane oraz ustawienia. Wciśnij anuluj, aby wznowić uruchamianie. - - - Cancel - Anuluj - - - Reboot - Uruchom ponownie - - - Confirm - Potwiedź - - - Unable to mount data partition. Press confirm to reset your device. - Partycja nie została zamontowana poprawnie. Wciśnij potwierdź, aby uruchomić ponownie urządzenie. - - - - RichTextDialog - - Ok - Ok - - - - SettingsWindow - - × - x - - - Device - Urządzenie - - - Network - Sieć - - - Toggles - Przełączniki - - - Software - Oprogramowanie - - - Navigation - Nawigacja - - - - Setup - - WARNING: Low Voltage - OSTRZEŻENIE: Niskie Napięcie - - - Power your device in a car with a harness or proceed at your own risk. - Podłącz swoje urządzenie do zasilania poprzez podłączenienie go do pojazdu lub kontynuuj na własną odpowiedzialność. - - - Power off - Wyłącz - - - Continue - Kontynuuj - - - Getting Started - Zacznij - - - Before we get on the road, let’s finish installation and cover some details. - Zanim ruszysz w drogę, dokończ instalację i podaj kilka szczegółów. - - - Connect to Wi-Fi - Połącz z Wi-Fi - - - Back - Wróć - - - Continue without Wi-Fi - Kontynuuj bez połączenia z Wif-Fi - - - Waiting for internet - Oczekiwanie na połączenie sieciowe - - - Choose Software to Install - Wybierz oprogramowanie do instalacji - - - Dashcam - Wideorejestrator - - - Custom Software - Własne oprogramowanie - - - Enter URL - Wprowadź adres URL - - - for Custom Software - do własnego oprogramowania - - - Downloading... - Pobieranie... - - - Download Failed - Pobieranie nie powiodło się - - - Ensure the entered URL is valid, and the device’s internet connection is good. - Upewnij się, że wpisany adres URL jest poprawny, a połączenie internetowe działa poprawnie. - - - Reboot device - Uruchom ponownie - - - Start over - Zacznij od początku - - - - SetupWidget - - Finish Setup - Zakończ konfigurację - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Sparuj swoje urządzenie z comma connect (connect.comma.ai) i wybierz swoją ofertę comma prime. - - - Pair device - Sparuj urządzenie - - - - Sidebar - - CONNECT - POŁĄCZENIE - - - OFFLINE - OFFLINE - - - ONLINE - ONLINE - - - ERROR - BŁĄD - - - TEMP - TEMP - - - HIGH - WYSOKA - - - GOOD - DOBRA - - - OK - OK - - - VEHICLE - POJAZD - - - NO - BRAK - - - PANDA - PANDA - - - GPS - GPS - - - SEARCH - SZUKAJ - - - -- - -- - - - Wi-Fi - Wi-FI - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Git Branch - Gałąź Git - - - Git Commit - Git commit - - - OS Version - Wersja systemu - - - Version - Wersja - - - Last Update Check - Ostatnie sprawdzenie aktualizacji - - - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - Ostatni raz kiedy openpilot znalazł aktualizację. Aktualizator może być uruchomiony wyłącznie wtedy, kiedy pojazd jest wyłączony. - - - Check for Update - Sprawdź uaktualnienia - - - CHECKING - SPRAWDZANIE - - - Switch Branch - Zmień gąłąź - - - ENTER - WPROWADŹ - - - The new branch will be pulled the next time the updater runs. - Nowa gałąź będzie pobrana przy następnym uruchomieniu aktualizatora. - - - Enter branch name - Wprowadź nazwę gałęzi - - - Uninstall %1 - Odinstaluj %1 - - - UNINSTALL - ODINSTALUJ - - - Are you sure you want to uninstall? - Czy na pewno chcesz odinstalować? - - - failed to fetch update - pobieranie aktualizacji zakończone niepowodzeniem - - - CHECK - SPRAWDŹ - - - Updates are only downloaded while the car is off. - - - - Current Version - - - - Download - - - - Install Update - - - - INSTALL - - - - Target Branch - - - - SELECT - - - - Select a branch - - - - - SshControl - - SSH Keys - Klucze SSH - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Ostrzeżenie: To spowoduje przekazanie dostępu do wszystkich Twoich publicznych kuczy z ustawień GitHuba. Nigdy nie wprowadzaj nazwy użytkownika innej niż swoja. Pracownik comma NIGDY nie poprosi o dodanie swojej nazwy uzytkownika. - - - ADD - DODAJ - - - Enter your GitHub username - Wpisz swoją nazwę użytkownika GitHub - - - LOADING - ŁADOWANIE - - - REMOVE - USUŃ - - - Username '%1' has no keys on GitHub - Użytkownik '%1' nie posiada żadnych kluczy na GitHubie - - - Request timed out - Limit czasu rządania - - - Username '%1' doesn't exist on GitHub - Użytkownik '%1' nie istnieje na GitHubie - - - - SshToggle - - Enable SSH - Włącz SSH - - - - TermsPage - - Terms & Conditions - Regulamin - - - Decline - Odrzuć - - - Scroll to accept - Przewiń w dół, aby zaakceptować - - - Agree - Zaakceptuj - - - - TogglesPanel - - Enable openpilot - Włącz openpilota - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Użyj openpilota do zachowania bezpiecznego odstępu między pojazdami i do asystowania w utrzymywaniu pasa ruchu. Twoja pełna uwaga jest wymagana przez cały czas korzystania z tej funkcji. Ustawienie to może być wdrożone wyłącznie wtedy, gdy pojazd jest wyłączony. - - - Enable Lane Departure Warnings - Włącz ostrzeganie przed zmianą pasa ruchu - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Otrzymuj alerty o powrocie na właściwy pas, kiedy Twój pojazd przekroczy linię bez włączonego kierunkowskazu jadąc powyżej 50 km/h (31 mph). - - - Use Metric System - Korzystaj z systemu metrycznego - - - Display speed in km/h instead of mph. - Wyświetl prędkość w km/h zamiast mph. - - - Record and Upload Driver Camera - Nagraj i prześlij nagranie z kamery kierowcy - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Prześlij dane z kamery skierowanej na kierowcę i pomóż poprawiać algorytm monitorowania kierowcy. - - - Disengage on Accelerator Pedal - Odłącz poprzez naciśnięcie gazu - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Po włączeniu, naciśnięcie na pedał gazu odłączy openpilota. - - - Show ETA in 24h Format - Pokaż oczekiwany czas dojazdu w formacie 24-godzinnym - - - Use 24h format instead of am/pm - Korzystaj z formatu 24-godzinnego zamiast 12-godzinnego - - - Show Map on Left Side of UI - Pokaż mapę po lewej stronie ekranu - - - Show map on left side when in split screen view. - Pokaż mapę po lewej stronie kiedy ekran jest podzielony. - - - openpilot Longitudinal Control - Kontrola wzdłużna openpilota - - - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - openpilot wyłączy radar samochodu i przejmie kontrolę nad gazem i hamulcem. Ostrzeżenie: wyłączony zostanie system AEB! - - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - - - - Experimental openpilot Longitudinal Control - - - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - - - - openpilot longitudinal control is not currently available for this car. - - - - Enable experimental longitudinal control to enable this. - - - - - Updater - - Update Required - Wymagana Aktualizacja - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Wymagana aktualizacja systemu operacyjnego. Aby przyspieszyć proces aktualizacji połącz swoje urzeądzenie do Wi-Fi. Rozmiar pobieranej paczki wynosi około 1GB. - - - Connect to Wi-Fi - Połącz się z Wi-Fi - - - Install - Zainstaluj - - - Back - Wróć - - - Loading... - Ładowanie... - - - Reboot - Uruchom ponownie - - - Update failed - Aktualizacja nie powiodła się - - - - WifiUI - - Scanning for networks... - Wyszukiwanie sieci... - - - CONNECTING... - ŁĄCZENIE... - - - FORGET - ZAPOMNIJ - - - Forget Wi-Fi Network "%1"? - Czy chcesz zapomnieć sieć "%1"? - - - diff --git a/selfdrive/ui/translations/pt-BR.ts b/selfdrive/ui/translations/pt-BR.ts deleted file mode 100644 index 77aa5e07c1..0000000000 --- a/selfdrive/ui/translations/pt-BR.ts +++ /dev/null @@ -1,1074 +0,0 @@ - - - - - AbstractAlert - - Close - Fechar - - - Reboot and Update - Reiniciar e Atualizar - - - - AdvancedNetworking - - Back - Voltar - - - Enable Tethering - Ativar Tether - - - Tethering Password - Senha Tethering - - - EDIT - EDITAR - - - Enter new tethering password - Insira nova senha tethering - - - IP Address - Endereço IP - - - Enable Roaming - Ativar Roaming - - - APN Setting - APN Config - - - Enter APN - Insira APN - - - leave blank for automatic configuration - deixe em branco para configuração automática - - - Cellular Metered - Plano de Dados Limitado - - - Hidden Network - Rede Oculta - - - CONNECT - CONECTE - - - Enter SSID - Digite o SSID - - - Enter password - Insira a senha - - - for "%1" - para "%1" - - - Prevent large data uploads when on a metered cellular connection - Previna o envio de grandes volumes de dados em conexões de celular com franquia de limite de dados - - - default - padrão - - - metered - limitada - - - unmetered - ilimitada - - - Wi-Fi Network Metered - Rede Wi-Fi com Franquia - - - Prevent large data uploads when on a metered Wi-Fi connection - Previna o envio de grandes volumes de dados em conexões Wi-Fi com franquia de limite de dados - - - - ConfirmationDialog - - Ok - OK - - - Cancel - Cancelar - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - Você precisa aceitar os Termos e Condições para utilizar openpilot. - - - Back - Voltar - - - Decline, uninstall %1 - Rejeitar, desintalar %1 - - - - DeveloperPanel - - Joystick Debug Mode - Modo Joystick Debug - - - Longitudinal Maneuver Mode - Modo Longitudinal Maneuver - - - openpilot Longitudinal Control (Alpha) - Controle Longitudinal openpilot (Embrionário) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - AVISO: o controle longitudinal openpilot está em estado embrionário para este carro e desativará a Frenagem Automática de Emergência (AEB). - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o embrionário controle longitudinal openpilot. - - - Enable ADB - Habilitar ADB - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB (Android Debug Bridge) permite conectar ao seu dispositivo por meio do USB ou através da rede. Veja https://docs.comma.ai/how-to/connect-to-comma para maiores informações. - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - N/A - - - Serial - Serial - - - Driver Camera - Câmera do Motorista - - - PREVIEW - VER - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Pré-visualizar a câmera voltada para o motorista para garantir que o monitoramento do sistema tenha uma boa visibilidade (veículo precisa estar desligado) - - - Reset Calibration - Reinicializar Calibragem - - - RESET - RESET - - - Are you sure you want to reset calibration? - Tem certeza que quer resetar a calibragem? - - - Review Training Guide - Revisar Guia de Treinamento - - - REVIEW - REVISAR - - - Review the rules, features, and limitations of openpilot - Revisar regras, aprimoramentos e limitações do openpilot - - - Are you sure you want to review the training guide? - Tem certeza que quer rever o treinamento? - - - Regulatory - Regulatório - - - VIEW - VER - - - Change Language - Alterar Idioma - - - CHANGE - ALTERAR - - - Select a language - Selecione o Idioma - - - Reboot - Reiniciar - - - Power Off - Desligar - - - Your device is pointed %1° %2 and %3° %4. - Seu dispositivo está montado %1° %2 e %3° %4. - - - down - baixo - - - up - cima - - - left - esquerda - - - right - direita - - - Are you sure you want to reboot? - Tem certeza que quer reiniciar? - - - Disengage to Reboot - Desacione para Reiniciar - - - Are you sure you want to power off? - Tem certeza que quer desligar? - - - Disengage to Power Off - Desacione para Desligar - - - Reset - Resetar - - - Review - Revisar - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Pareie seu dispositivo com comma connect (connect.comma.ai) e reivindique sua oferta de comma prime. - - - Pair Device - Parear Dispositivo - - - PAIR - PAREAR - - - Disengage to Reset Calibration - Desacione para Resetar a Calibração - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - O openpilot exige que o dispositivo seja montado dentro de 4° para a esquerda ou direita e dentro de 5° para cima ou 9° para baixo. - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - O openpilot está em constante calibração, raramente sendo necessário redefini-lo. Redefinir a calibração reiniciará o openpilot se o carro estiver ligado. - - - - -Steering lag calibration is %1% complete. - - -A calibração do atraso da direção está %1% concluída. - - - - -Steering lag calibration is complete. - - -A calibração do atraso da direção foi concluída. - - - Steering torque response calibration is %1% complete. - A calibração da resposta de torque da direção está %1% concluída. - - - Steering torque response calibration is complete. - A calibração da resposta do torque da direção foi concluída. - - - - DriverViewWindow - - camera starting - câmera iniciando - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - MODO EXPERIMENTAL ON - - - CHILL MODE ON - MODO CHILL ON - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - O openpilot aprende a dirigir observando humanos, como você, dirigirem. - -O Modo Firehose permite maximizar o envio de dados de treinamento para melhorar os modelos de direção do openpilot. Mais dados significam modelos maiores, o que resulta em um Modo Experimental melhor. - - - Firehose Mode: ACTIVE - Modo Firehose: ATIVO - - - ACTIVE - ATIVO - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - Para maior eficácia, leve seu dispositivo para dentro de casa e conecte-o a um bom adaptador USB-C e Wi-Fi semanalmente.<br><br>O Modo Firehose também pode funcionar enquanto você dirige, se estiver conectado a um hotspot ou a um chip SIM com dados ilimitados.<br><br><br><b>Perguntas Frequentes</b><br><br><i>Importa como ou onde eu dirijo?</i> Não, basta dirigir normalmente.<br><br><i>Todos os meus segmentos são enviados no Modo Firehose?</i> Não, selecionamos apenas um subconjunto dos seus segmentos.<br><br><i>Qual é um bom adaptador USB-C?</i> Qualquer carregador rápido de telefone ou laptop deve ser suficiente.<br><br><i>Importa qual software eu uso?</i> Sim, apenas o openpilot oficial (e alguns forks específicos) podem ser usados para treinamento. - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>%n segmento</b> da sua direção está no conjunto de dados de treinamento até agora. - <b>%n segmentos</b> da sua direção estão no conjunto de dados de treinamento até agora. - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INATIVO</span>: conecte-se a uma rede sem limite <br> de dados - - - Firehose Mode - Modo Firehose - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - LIMITE - - - - InputDialog - - Cancel - Cancelar - - - Need at least %n character(s)! - - Necessita no mínimo %n caractere! - Necessita no mínimo %n caracteres! - - - - - MultiOptionDialog - - Select - Selecione - - - Cancel - Cancelar - - - - Networking - - Advanced - Avançado - - - Enter password - Insira a senha - - - for "%1" - para "%1" - - - Wrong password - Senha incorreta - - - - OffroadAlert - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Conecte-se imediatamente à internet para verificar se há atualizações. Se você não se conectar à internet em %1 não será possível acionar o openpilot. - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - Conecte-se à internet para verificar se há atualizações. O openpilot não será iniciado automaticamente até que ele se conecte à internet para verificar se há atualizações. - - - Unable to download updates -%1 - Não é possível baixar atualizações -%1 - - - Taking camera snapshots. System won't start until finished. - Tirando fotos da câmera. O sistema não será iniciado até terminar. - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - Uma atualização para o sistema operacional do seu dispositivo está sendo baixada em segundo plano. Você será solicitado a atualizar quando estiver pronto para instalar. - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - O openpilot não conseguiu identificar o seu carro. Seu carro não é suportado ou seus ECUs não são reconhecidos. Envie um pull request para adicionar as versões de firmware ao veículo adequado. Precisa de ajuda? Junte-se discord.comma.ai. - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - O openpilot detectou uma mudança na posição de montagem do dispositivo. Verifique se o dispositivo está totalmente encaixado no suporte e se o suporte está firmemente preso ao para-brisa. - - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - Temperatura do dispositivo muito alta. O sistema está sendo resfriado antes de iniciar. A temperatura atual do componente interno é: %1 - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - O dispositivo não conseguiu se registrar no backend da comma.ai. Ele não se conecta nem faz upload para os servidores da comma.ai e não recebe suporte da comma.ai. Se este for um dispositivo adquirido em comma.ai/shop, abra um ticket em https://comma.ai/support. - - - Acknowledge Excessive Actuation - Reconhecer Atuação Excessiva - - - Snooze Update - Adiar Atualização - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - openpilot detectou atuação excessiva de %1 na sua última condução. Entre em contato com o suporte em https://comma.ai/support e compartilhe o Dongle ID do seu dispositivo para solução de problemas. - - - - OffroadHome - - UPDATE - ATUALIZAÇÃO - - - ALERTS - ALERTAS - - - ALERT - ALERTA - - - - OnroadAlerts - - openpilot Unavailable - openpilot Indisponível - - - TAKE CONTROL IMMEDIATELY - ASSUMA IMEDIATAMENTE - - - Reboot Device - Reinicie o Dispositivo - - - Waiting to start - Aguardando para iniciar - - - System Unresponsive - Sistema sem Resposta - - - - PairingPopup - - Pair your device to your comma account - Pareie seu dispositivo à sua conta comma - - - Go to https://connect.comma.ai on your phone - navegue até https://connect.comma.ai no seu telefone - - - Click "add new device" and scan the QR code on the right - Clique "add new device" e escaneie o QR code a seguir - - - Bookmark connect.comma.ai to your home screen to use it like an app - Salve connect.comma.ai como sua página inicial para utilizar como um app - - - Please connect to Wi-Fi to complete initial pairing - Por favor conecte ao Wi-Fi para completar o pareamento inicial - - - - ParamControl - - Cancel - Cancelar - - - Enable - Ativar - - - - PrimeAdWidget - - Upgrade Now - Atualizar Agora - - - Become a comma prime member at connect.comma.ai - Seja um membro comma prime em connect.comma.ai - - - PRIME FEATURES: - BENEFÍCIOS PRIME: - - - Remote access - Acesso remoto (proxy comma) - - - 24/7 LTE connectivity - Conectividade LTE (só nos EUA) - - - 1 year of drive storage - 1 ano de dados em nuvem - - - Remote snapshots - Captura remota - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ INSCRITO - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - há %n minuto - há %n minutos - - - - %n hour(s) ago - - há %n hora - há %n horas - - - - %n day(s) ago - - há %n dia - há %n dias - - - - now - agora - - - - SettingsWindow - - × - × - - - Device - Dispositivo - - - Network - Rede - - - Toggles - Ajustes - - - Software - Software - - - Developer - Desenvdor - - - Firehose - Firehose - - - - SetupWidget - - Finish Setup - Concluir - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Pareie seu dispositivo com comma connect (connect.comma.ai) e reivindique sua oferta de comma prime. - - - Pair device - Parear dispositivo - - - - Sidebar - - CONNECT - CONEXÃO - - - OFFLINE - OFFLINE - - - ONLINE - ONLINE - - - ERROR - ERRO - - - TEMP - TEMP - - - HIGH - ALTA - - - GOOD - BOA - - - OK - OK - - - VEHICLE - VEÍCULO - - - NO - SEM - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - Atualizações baixadas durante o motor desligado. - - - Current Version - Versão Atual - - - Download - Download - - - Install Update - Instalar Atualização - - - INSTALL - INSTALAR - - - Target Branch - Alterar Branch - - - SELECT - SELECIONE - - - Select a branch - Selecione uma branch - - - UNINSTALL - REMOVER - - - Uninstall %1 - Desinstalar o %1 - - - Are you sure you want to uninstall? - Tem certeza que quer desinstalar? - - - CHECK - VERIFICAR - - - Uninstall - Desinstalar - - - failed to check for update - falha ao verificar por atualizações - - - up to date, last checked %1 - atualizado, última verificação %1 - - - DOWNLOAD - BAIXAR - - - update available - atualização disponível - - - never - nunca - - - - SshControl - - SSH Keys - Chave SSH - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Aviso: isso concede acesso SSH a todas as chaves públicas nas configurações do GitHub. Nunca insira um nome de usuário do GitHub que não seja o seu. Um funcionário da comma NUNCA pedirá que você adicione seu nome de usuário do GitHub. - - - ADD - ADICIONAR - - - Enter your GitHub username - Insira seu nome de usuário do GitHub - - - LOADING - CARREGANDO - - - REMOVE - REMOVER - - - Username '%1' has no keys on GitHub - Usuário "%1” não possui chaves no GitHub - - - Request timed out - A solicitação expirou - - - Username '%1' doesn't exist on GitHub - Usuário '%1' não existe no GitHub - - - - SshToggle - - Enable SSH - Habilitar SSH - - - - TermsPage - - Decline - Declinar - - - Agree - Concordo - - - Welcome to openpilot - Bem vindo ao openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - Você deve aceitar os Termos e Condições para usar o openpilot. Leia os termos mais recentes em <span style='color: #465BEA;'>https://comma.ai/terms</span> antes de continuar. - - - - TogglesPanel - - Enable openpilot - Ativar openpilot - - - Enable Lane Departure Warnings - Ativar Avisos de Saída de Faixa - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Receba alertas para voltar para a pista se o seu veículo sair da faixa e a seta não tiver sido acionada previamente quando em velocidades superiores a 50 km/h. - - - Use Metric System - Usar Sistema Métrico - - - Display speed in km/h instead of mph. - Exibir velocidade em km/h invés de mph. - - - Record and Upload Driver Camera - Gravar e Upload Câmera Motorista - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Upload dados da câmera voltada para o motorista e ajude a melhorar o algoritmo de monitoramentor. - - - Disengage on Accelerator Pedal - Desacionar com Pedal do Acelerador - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Quando ativado, pressionar o pedal do acelerador desacionará o openpilot. - - - Experimental Mode - Modo Experimental - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-embrionário</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Deixe o modelo de IA controlar o acelerador e os freios. O openpilot irá dirigir como pensa que um humano faria, incluindo parar em sinais vermelhos e sinais de parada. Uma vez que o modelo de condução decide a velocidade a conduzir, a velocidade definida apenas funcionará como um limite superior. Este é um recurso de qualidade embrionária; erros devem ser esperados. - - - New Driving Visualization - Nova Visualização de Condução - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - O modo Experimental está atualmente indisponível para este carro já que o ACC original do carro é usado para controle longitudinal. - - - openpilot longitudinal control may come in a future update. - O controle longitudinal openpilot poderá vir em uma atualização futura. - - - Aggressive - Disputa - - - Standard - Neutro - - - Relaxed - Calmo - - - Driving Personality - Temperamento de Direção - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Uma versão embrionária do controle longitudinal openpilot pode ser testada em conjunto com o modo Experimental, em branches que não sejam de produção. - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - Habilite o controle longitudinal (embrionário) openpilot para permitir o modo Experimental. - - - End-to-End Longitudinal Control - Controle Longitudinal de Ponta a Ponta - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Neutro é o recomendado. No modo disputa o openpilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o openpilot se manterá mais longe do carro da frente. Em carros compatíveis, você pode alternar esses temperamentos com o botão de distância do volante. - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - A visualização de condução fará a transição para a câmera grande angular voltada para a estrada em baixas velocidades para mostrar melhor algumas curvas. O logotipo do modo Experimental também será mostrado no canto superior direito. - - - Always-On Driver Monitoring - Monitoramento do Motorista Sempre Ativo - - - Enable driver monitoring even when openpilot is not engaged. - Habilite o monitoramento do motorista mesmo quando o openpilot não estiver acionado. - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - Use o sistema openpilot para controle de cruzeiro adaptativo e assistência ao motorista de manutenção de faixa. Sua atenção é necessária o tempo todo para usar esse recurso. - - - Changing this setting will restart openpilot if the car is powered on. - Alterar esta configuração fará com que o openpilot reinicie se o carro estiver ligado. - - - Record and Upload Microphone Audio - Gravar e Fazer Upload do Áudio do Microfone - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - Grave e armazene o áudio do microfone enquanto estiver dirigindo. O áudio será incluído ao vídeo dashcam no comma connect. - - - - WiFiPromptWidget - - Open - Abrir - - - Maximize your training data uploads to improve openpilot's driving models. - Maximize seus envios de dados de treinamento para melhorar os modelos de direção do openpilot. - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Modo Firehose <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - Procurando redes... - - - CONNECTING... - CONECTANDO... - - - FORGET - ESQUECER - - - Forget Wi-Fi Network "%1"? - Esquecer Rede Wi-Fi "%1"? - - - Forget - Esquecer - - - diff --git a/selfdrive/ui/translations/th.ts b/selfdrive/ui/translations/th.ts deleted file mode 100644 index 9bd6822086..0000000000 --- a/selfdrive/ui/translations/th.ts +++ /dev/null @@ -1,1065 +0,0 @@ - - - - - AbstractAlert - - Close - ปิด - - - Reboot and Update - รีบูตและอัปเดต - - - - AdvancedNetworking - - Back - ย้อนกลับ - - - Enable Tethering - ปล่อยฮอตสปอต - - - Tethering Password - รหัสผ่านฮอตสปอต - - - EDIT - แก้ไข - - - Enter new tethering password - ป้อนรหัสผ่านฮอตสปอตใหม่ - - - IP Address - หมายเลขไอพี - - - Enable Roaming - เปิดใช้งานโรมมิ่ง - - - APN Setting - ตั้งค่า APN - - - Enter APN - ป้อนค่า APN - - - leave blank for automatic configuration - เว้นว่างเพื่อตั้งค่าอัตโนมัติ - - - Cellular Metered - ลดการส่งข้อมูลผ่านเซลลูล่าร์ - - - Hidden Network - เครือข่ายที่ซ่อนอยู่ - - - CONNECT - เชื่อมต่อ - - - Enter SSID - ป้อนค่า SSID - - - Enter password - ใส่รหัสผ่าน - - - for "%1" - สำหรับ "%1" - - - Prevent large data uploads when on a metered cellular connection - - - - default - - - - metered - - - - unmetered - - - - Wi-Fi Network Metered - - - - Prevent large data uploads when on a metered Wi-Fi connection - - - - - ConfirmationDialog - - Ok - ตกลง - - - Cancel - ยกเลิก - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - คุณต้องยอมรับเงื่อนไขและข้อตกลง เพื่อใช้งาน openpilot - - - Back - ย้อนกลับ - - - Decline, uninstall %1 - ปฏิเสธ และถอนการติดตั้ง %1 - - - - DeveloperPanel - - Joystick Debug Mode - โหมดดีบักจอยสติ๊ก - - - Longitudinal Maneuver Mode - โหมดการควบคุมการเร่ง/เบรค - - - openpilot Longitudinal Control (Alpha) - ระบบควบคุมการเร่ง/เบรคโดย openpilot (Alpha) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในสถานะ alpha และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - โดยปกติสำหรับรถคันนี้ openpilot จะควบคุมการเร่ง/เบรคด้วยระบบ ACC จากโรงงาน แทนการควยคุมโดย openpilot เปิดสวิตซ์นี้เพื่อให้ openpilot ควบคุมการเร่ง/เบรค แนะนำให้เปิดโหมดทดลองเมื่อต้องการให้ openpilot ควบคุมการเร่ง/เบรค ซึ่งอยู่ในสถานะ alpha - - - Enable ADB - เปิด ADB - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB (Android Debug Bridge) อนุญาตให้เชื่อมต่ออุปกรณ์ของคุณผ่าน USB หรือผ่านเครือข่าย ดูข้อมูลเพิ่มเติมที่ https://docs.comma.ai/how-to/connect-to-comma - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - ไม่มี - - - Serial - ซีเรียล - - - Driver Camera - กล้องฝั่งคนขับ - - - PREVIEW - แสดงภาพ - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - ดูภาพตัวอย่างกล้องที่หันเข้าหาคนขับเพื่อให้แน่ใจว่าการตรวจสอบคนขับมีทัศนวิสัยที่ดี (รถต้องดับเครื่องยนต์) - - - Reset Calibration - รีเซ็ตการคาลิเบรท - - - RESET - รีเซ็ต - - - Are you sure you want to reset calibration? - คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตการคาลิเบรท? - - - Review Training Guide - ทบทวนคู่มือการใช้งาน - - - REVIEW - ทบทวน - - - Review the rules, features, and limitations of openpilot - ตรวจสอบกฎ คุณสมบัติ และข้อจำกัดของ openpilot - - - Are you sure you want to review the training guide? - คุณแน่ใจหรือไม่ว่าต้องการทบทวนคู่มือการใช้งาน? - - - Regulatory - ระเบียบข้อบังคับ - - - VIEW - ดู - - - Change Language - เปลี่ยนภาษา - - - CHANGE - เปลี่ยน - - - Select a language - เลือกภาษา - - - Reboot - รีบูต - - - Power Off - ปิดเครื่อง - - - Your device is pointed %1° %2 and %3° %4. - อุปกรณ์ของคุณเอียงไปทาง %2 %1° และ %4 %3° - - - down - ด้านล่าง - - - up - ด้านบน - - - left - ด้านซ้าย - - - right - ด้านขวา - - - Are you sure you want to reboot? - คุณแน่ใจหรือไม่ว่าต้องการรีบูต? - - - Disengage to Reboot - ยกเลิกระบบช่วยขับเพื่อรีบูต - - - Are you sure you want to power off? - คุณแน่ใจหรือไม่ว่าต้องการปิดเครื่อง? - - - Disengage to Power Off - ยกเลิกระบบช่วยขับเพื่อปิดเครื่อง - - - Reset - รีเซ็ต - - - Review - ทบทวน - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - จับคู่อุปกรณ์ของคุณกับ comma connect (connect.comma.ai) และรับข้อเสนอ comma prime ของคุณ - - - Pair Device - จับคู่อุปกรณ์ - - - PAIR - จับคู่ - - - Disengage to Reset Calibration - - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - -Steering lag calibration is %1% complete. - - - - - -Steering lag calibration is complete. - - - - Steering torque response calibration is %1% complete. - - - - Steering torque response calibration is complete. - - - - - DriverViewWindow - - camera starting - กำลังเปิดกล้อง - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - คุณกำลังใช้โหมดทดลอง - - - CHILL MODE ON - คุณกำลังใช้โหมดชิล - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - openpilot เรียนรู้วิธีขับรถจากการเฝ้าดูการขับขี่ของมนุษย์เช่นคุณ - -โหมดสายยางดับเพลิงช่วยให้คุณอัปโหลดข้อมูลการฝึกฝนได้มากที่สุด เพื่อนำไปพัฒนาโมเดลการขับขี่ของ openpilot ข้อมูลที่มากขึ้นหมายถึงโมเดลที่ใหญ่ขึ้น และนั่นหมายถึงโหมดทดลองที่ดีขึ้น - - - Firehose Mode: ACTIVE - โหมดสายยางดับเพลิง: เปิดใช้งาน - - - ACTIVE - เปิดใช้งาน - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - เพื่อประสิทธิภาพสูงสุด ควรนำอุปกรณ์เข้ามาข้างใน เชื่อมต่อกับอะแดปเตอร์ USB-C คุณภาพดี และ Wi-Fi สัปดาห์ละครั้ง<br><br>โหมดสายยางดับเพลิงยังสามารถทำงานระหว่างขับรถได้ หากเชื่อมต่อกับฮอตสปอตหรือซิมการ์ดที่มีเน็ตไม่จำกัด<br><br><br><b>คำถามที่พบบ่อย</b><br><br><i>วิธีการขับหรือสถานที่ขับขี่มีผลหรือไม่?</i>ไม่มีผล แค่ขับขี่ตามปกติของคุณ<br><br><i>เซกเมนต์ทั้งหมดของฉันจะถูกดึงข้อมูลในโหมดสายยางดับเพลิงหรือไม่?</i>ไม่ใช่ เราจะเลือกดึงข้อมูลเพียงบางส่วนจากเซกเมนต์ของคุณ<br><br><i>อะแดปเตอร์ USB-C แบบไหนดี?</i>ที่ชาร์จเร็วของโทรศัพท์หรือแล็ปท็อปแบบใดก็ได้ สามารถใช้ได้<br><br><i>ซอฟต์แวร์ที่ใช้มีผลหรือไม่?</i>มีผล เฉพาะ openpilot ตัวหลัก (และ fork เฉพาะบางตัว) เท่านั้น ที่สามารถนำข้อมูลไปใช้ฝึกฝนโมเดลได้ - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - มีการขับขี่ของคุณ <b>%n เซกเมนต์</b> อยู่ในชุดข้อมูลการฝึกฝนแล้วในขณะนี้ - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>ไม่เปิดใช้งาน</span>: เชื่อมต่อกับเครือข่ายที่ไม่จำกัดข้อมูล - - - Firehose Mode - - - - - HudRenderer - - km/h - กม./ชม. - - - mph - ไมล์/ชม. - - - MAX - สูงสุด - - - - InputDialog - - Cancel - ยกเลิก - - - Need at least %n character(s)! - - ต้องการอย่างน้อย %n ตัวอักษร! - - - - - MultiOptionDialog - - Select - เลือก - - - Cancel - ยกเลิก - - - - Networking - - Advanced - ขั้นสูง - - - Enter password - ใส่รหัสผ่าน - - - for "%1" - สำหรับ "%1" - - - Wrong password - รหัสผ่านผิด - - - - OffroadAlert - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - อุณหภูมิของอุปกรณ์สูงเกินไป ระบบกำลังทำความเย็นก่อนเริ่ม อุณหภูมิของชิ้นส่วนภายในปัจจุบัน: %1 - - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - กรุณาเชื่อมต่ออินเตอร์เน็ตเพื่อตรวจสอบอัปเดทเดี๋ยวนี้ ถ้าคุณไม่เชื่อมต่ออินเตอร์เน็ต openpilot จะไม่ทำงานในอีก %1 - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - กรุณาเชื่อมต่ออินเตอร์เน็ตเพื่อตรวจสอบอัปเดท openpilot จะไม่เริ่มทำงานอัตโนมัติจนกว่าจะได้เชื่อมต่อกับอินเตอร์เน็ตเพื่อตรวจสอบอัปเดท - - - Unable to download updates -%1 - ไม่สามารถดาวน์โหลดอัพเดทได้ -%1 - - - Taking camera snapshots. System won't start until finished. - กล้องกำลังถ่ายภาพ ระบบจะไม่เริ่มทำงานจนกว่าจะเสร็จ - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - กำลังดาวน์โหลดอัปเดทสำหรับระบบปฏิบัติการอยู่เบื้องหลัง คุณจะได้รับการแจ้งเตือนเมื่อระบบพร้อมสำหรับการติดตั้ง - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot ไม่สามารถระบุรถยนต์ของคุณได้ ระบบอาจไม่รองรับรถยนต์ของคุณหรือไม่รู้จัก ECU กรุณาส่ง pull request เพื่อเพิ่มรุ่นของเฟิร์มแวร์ให้กับรถยนต์ที่เหมาะสม หากต้องการความช่วยเหลือให้เข้าร่วม discord.comma.ai - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot ตรวจพบการเปลี่ยนแปลงของตำแหน่งที่ติดตั้ง กรุณาตรวจสอบว่าได้เลื่อนอุปกรณ์เข้ากับจุดติดตั้งจนสุดแล้ว และจุดติดตั้งได้ยึดติดกับกระจกหน้าอย่างแน่นหนา - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - - - - Acknowledge Excessive Actuation - - - - Snooze Update - เลื่อนการอัปเดต - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - อัปเดต - - - ALERTS - การแจ้งเตือน - - - ALERT - การแจ้งเตือน - - - - OnroadAlerts - - openpilot Unavailable - openpilot ไม่สามารถใช้งานได้ - - - TAKE CONTROL IMMEDIATELY - เข้าควบคุมรถเดี๋ยวนี้ - - - Reboot Device - รีบูตอุปกรณ์ - - - Waiting to start - รอเริ่มทำงาน - - - System Unresponsive - ระบบไม่ตอบสนอง - - - - PairingPopup - - Pair your device to your comma account - จับคู่อุปกรณ์ของคุณกับบัญชี comma ของคุณ - - - Go to https://connect.comma.ai on your phone - ไปที่ https://connect.comma.ai ด้วยโทรศัพท์ของคุณ - - - Click "add new device" and scan the QR code on the right - กดที่ "add new device" และสแกนคิวอาร์โค้ดทางด้านขวา - - - Bookmark connect.comma.ai to your home screen to use it like an app - จดจำ connect.comma.ai โดยการเพิ่มไปยังหน้าจอโฮม เพื่อใช้งานเหมือนเป็นแอปพลิเคชัน - - - Please connect to Wi-Fi to complete initial pairing - กรุณาเชื่อมต่อ Wi-Fi เพื่อทำการจับคู่ครั้งแรกให้เสร็จสิ้น - - - - ParamControl - - Enable - เปิดใช้งาน - - - Cancel - ยกเลิก - - - - PrimeAdWidget - - Upgrade Now - อัพเกรดเดี๋ยวนี้ - - - Become a comma prime member at connect.comma.ai - สมัครสมาชิก comma prime ได้ที่ connect.comma.ai - - - PRIME FEATURES: - คุณสมบัติของ PRIME: - - - Remote access - การเข้าถึงระยะไกล - - - 24/7 LTE connectivity - การเชื่อมต่อ LTE แบบ 24/7 - - - 1 year of drive storage - จัดเก็บข้อมูลการขับขี่นาน 1 ปี - - - Remote snapshots - ภาพถ่ายระยะไกล - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ สมัครสำเร็จ - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - %n นาทีที่แล้ว - - - - %n hour(s) ago - - %n ชั่วโมงที่แล้ว - - - - %n day(s) ago - - %n วันที่แล้ว - - - - now - ตอนนี้ - - - - SettingsWindow - - × - × - - - Device - อุปกรณ์ - - - Network - เครือข่าย - - - Toggles - ตัวเลือก - - - Software - ซอฟต์แวร์ - - - Developer - นักพัฒนา - - - Firehose - สายยางดับเพลิง - - - - SetupWidget - - Finish Setup - ตั้งค่าเสร็จสิ้น - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - จับคู่อุปกรณ์ของคุณกับ comma connect (connect.comma.ai) และรับข้อเสนอ comma prime ของคุณ - - - Pair device - จับคู่อุปกรณ์ - - - - Sidebar - - CONNECT - เชื่อมต่อ - - - OFFLINE - ออฟไลน์ - - - ONLINE - ออนไลน์ - - - ERROR - เกิดข้อผิดพลาด - - - TEMP - อุณหภูมิ - - - HIGH - สูง - - - GOOD - ดี - - - OK - พอใช้ - - - VEHICLE - รถยนต์ - - - NO - ไม่พบ - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Uninstall %1 - ถอนการติดตั้ง %1 - - - UNINSTALL - ถอนการติดตั้ง - - - Are you sure you want to uninstall? - คุณแน่ใจหรือไม่ว่าต้องการถอนการติดตั้ง? - - - CHECK - ตรวจสอบ - - - Updates are only downloaded while the car is off. - ตัวอัปเดตจะดำเนินการดาวน์โหลดเมื่อรถดับเครื่องยนต์อยู่เท่านั้น - - - Current Version - เวอร์ชั่นปัจจุบัน - - - Download - ดาวน์โหลด - - - Install Update - ติดตั้งตัวอัปเดต - - - INSTALL - ติดตั้ง - - - Target Branch - Branch ที่เลือก - - - SELECT - เลือก - - - Select a branch - เลือก Branch - - - Uninstall - ถอนการติดตั้ง - - - failed to check for update - ไม่สามารถตรวจสอบอัปเดตได้ - - - DOWNLOAD - ดาวน์โหลด - - - update available - มีอัปเดตใหม่ - - - never - ไม่เคย - - - up to date, last checked %1 - ล่าสุดแล้ว ตรวจสอบครั้งสุดท้ายเมื่อ %1 - - - - SshControl - - SSH Keys - คีย์ SSH - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - คำเตือน: สิ่งนี้ให้สิทธิ์ SSH เข้าถึงคีย์สาธารณะทั้งหมดใน GitHub ของคุณ อย่าป้อนชื่อผู้ใช้ GitHub อื่นนอกเหนือจากของคุณเอง พนักงาน comma จะไม่ขอให้คุณเพิ่มชื่อผู้ใช้ GitHub ของพวกเขา - - - ADD - เพิ่ม - - - Enter your GitHub username - ป้อนชื่อผู้ใช้ GitHub ของคุณ - - - LOADING - กำลังโหลด - - - REMOVE - ลบ - - - Username '%1' has no keys on GitHub - ชื่อผู้ใช้ '%1' ไม่มีคีย์บน GitHub - - - Request timed out - ตรวจสอบไม่สำเร็จ เนื่องจากใช้เวลามากเกินไป - - - Username '%1' doesn't exist on GitHub - ไม่พบชื่อผู้ใช้ '%1' บน GitHub - - - - SshToggle - - Enable SSH - เปิดใช้งาน SSH - - - - TermsPage - - Decline - ปฏิเสธ - - - Agree - ยอมรับ - - - Welcome to openpilot - ยินดีต้อนรับสู่ openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - คุณต้องยอมรับข้อกำหนดและเงื่อนไขเพื่อใช้งาน openpilot อ่านข้อกำหนดล่าสุดได้ที่ <span style='color: #465BEA;'>https://comma.ai/terms</span> ก่อนดำเนินการต่อ - - - - TogglesPanel - - Enable openpilot - เปิดใช้งาน openpilot - - - Enable Lane Departure Warnings - เปิดใช้งานการเตือนการออกนอกเลน - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - รับการแจ้งเตือนให้เลี้ยวกลับเข้าเลนเมื่อรถของคุณตรวจพบการข้ามช่องจราจรโดยไม่เปิดสัญญาณไฟเลี้ยวในขณะขับขี่ที่ความเร็วเกิน 31 ไมล์ต่อชั่วโมง (50 กม./ชม) - - - Use Metric System - ใช้ระบบเมตริก - - - Display speed in km/h instead of mph. - แสดงความเร็วเป็น กม./ชม. แทน ไมล์/ชั่วโมง - - - Record and Upload Driver Camera - บันทึกและอัปโหลดภาพจากกล้องคนขับ - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - อัปโหลดข้อมูลจากกล้องที่หันหน้าไปทางคนขับ และช่วยปรับปรุงอัลกอริธึมการตรวจสอบผู้ขับขี่ - - - Disengage on Accelerator Pedal - ยกเลิกระบบช่วยขับเมื่อเหยียบคันเร่ง - - - When enabled, pressing the accelerator pedal will disengage openpilot. - เมื่อเปิดใช้งาน การกดแป้นคันเร่งจะเป็นการยกเลิกระบบช่วยขับโดย openpilot - - - Experimental Mode - โหมดทดลอง - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - โดยปกติ openpilot จะขับใน<b>โหมดชิล</b> เปิดโหมดทดลองเพื่อใช้<b>ความสามารถในขั้นพัฒนา</b> ซึ่งยังไม่พร้อมสำหรับโหมดชิล ความสามารถในขั้นพัฒนามีดังนี้: - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - ให้ openpilot ควบคุมการเร่ง/เบรค โดย openpilot จะขับอย่างที่มนุษย์คิด รวมถึงการหยุดที่ไฟแดง และป้ายหยุดรถ เนื่องจาก openpilot จะกำหนดความเร็วในการขับด้วยตัวเอง การตั้งความเร็วจะเป็นเพียงการกำหนดความเร็วสูงสูดเท่านั้น ความสามารถนี้ยังอยู่ในขั้นพัฒนา อาจเกิดข้อผิดพลาดขึ้นได้ - - - New Driving Visualization - การแสดงภาพการขับขี่แบบใหม่ - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - ขณะนี้โหมดทดลองไม่สามารถใช้งานได้ในรถคันนี้ เนื่องจากเปิดใช้ระบบควบคุมการเร่ง/เบรคของรถที่ติดตั้งจากโรงงานอยู่ - - - openpilot longitudinal control may come in a future update. - ระบบควบคุมการเร่ง/เบรคโดย openpilot อาจมาในการอัปเดตในอนาคต - - - Aggressive - ดุดัน - - - Standard - มาตรฐาน - - - Relaxed - ผ่อนคลาย - - - Driving Personality - บุคลิกการขับขี่ - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - ระบบควบคุมการเร่ง/เบรคโดย openpilot เวอร์ชัน alpha สามารถทดสอบได้พร้อมกับโหมดการทดลอง บน branch ที่กำลังพัฒนา - - - End-to-End Longitudinal Control - ควบคุมเร่ง/เบรคแบบ End-to-End - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - เปิดระบบควบคุมการเร่ง/เบรคโดย openpilot (alpha) เพื่อเปิดใช้งานโหมดทดลอง - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - แนะนำให้ใช้แบบมาตรฐาน ในโหมดดุดัน openpilot จะตามรถคันหน้าใกล้ขึ้นและเร่งและเบรคแบบดุดันมากขึ้น ในโหมดผ่อนคลาย openpilot จะอยู่ห่างจากรถคันหน้ามากขึ้น ในรถรุ่นที่รองรับคุณสามารถเปลี่ยนบุคลิกไปแบบต่าง ๆ โดยใช้ปุ่มปรับระยะห่างบนพวงมาลัย - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - การแสดงภาพการขับขี่จะเปลี่ยนไปใช้กล้องมุมกว้างที่หันหน้าไปทางถนนเมื่ออยู่ในความเร็วต่ำ เพื่อแสดงภาพการเลี้ยวที่ดีขึ้น โลโก้โหมดการทดลองจะแสดงที่มุมบนขวาด้วย - - - Always-On Driver Monitoring - การเฝ้าระวังผู้ขับขี่ตลอดเวลา - - - Enable driver monitoring even when openpilot is not engaged. - เปิดใช้งานการเฝ้าระวังผู้ขับขี่แม้เมื่อ openpilot ไม่ได้เข้าควบคุมอยู่ - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Record and Upload Microphone Audio - - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - WiFiPromptWidget - - Open - เปิด - - - Maximize your training data uploads to improve openpilot's driving models. - อัปโหลดข้อมูลการฝึกฝนให้ได้มากที่สุด เพื่อพัฒนาโมเดลการขับขี่ของ openpilot - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> โหมดสายยางดับเพลิง <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - กำลังสแกนหาเครือข่าย... - - - CONNECTING... - กำลังเชื่อมต่อ... - - - FORGET - เลิกใช้ - - - Forget Wi-Fi Network "%1"? - เลิกใช้เครือข่าย Wi-Fi "%1"? - - - Forget - เลิกใช้ - - - diff --git a/selfdrive/ui/translations/tr.ts b/selfdrive/ui/translations/tr.ts deleted file mode 100644 index 7c6c692d54..0000000000 --- a/selfdrive/ui/translations/tr.ts +++ /dev/null @@ -1,1062 +0,0 @@ - - - - - AbstractAlert - - Close - Kapat - - - Reboot and Update - Güncelle ve Yeniden başlat - - - - AdvancedNetworking - - Back - Geri dön - - - Enable Tethering - Kişisel erişim noktasını aç - - - Tethering Password - Kişisel erişim noktasının parolası - - - EDIT - DÜZENLE - - - Enter new tethering password - Erişim noktasına yeni bir sonraki başlatılışında çekilir. parola belirleyin. - - - IP Address - IP Adresi - - - Enable Roaming - Hücresel veri aç - - - APN Setting - APN Ayarları - - - Enter APN - APN Gir - - - leave blank for automatic configuration - otomatik yapılandırma için boş bırakın - - - Cellular Metered - - - - Hidden Network - - - - CONNECT - BAĞLANTI - - - Enter SSID - APN Gir - - - Enter password - Parolayı girin - - - for "%1" - için "%1" - - - Prevent large data uploads when on a metered cellular connection - - - - default - - - - metered - - - - unmetered - - - - Wi-Fi Network Metered - - - - Prevent large data uploads when on a metered Wi-Fi connection - - - - - ConfirmationDialog - - Ok - Tamam - - - Cancel - Vazgeç - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - Openpilotu kullanmak için Kullanıcı Koşullarını kabul etmelisiniz. - - - Back - Geri - - - Decline, uninstall %1 - Reddet, Kurulumu kaldır. %1 - - - - DeveloperPanel - - Joystick Debug Mode - - - - Longitudinal Maneuver Mode - - - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - Enable ADB - - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - - - - - DevicePanel - - Dongle ID - Adaptör ID - - - N/A - N/A - - - Serial - Seri Numara - - - Driver Camera - Sürücü Kamerası - - - PREVIEW - ÖN İZLEME - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Sürücü kamerasının görüş açısını test etmek için kamerayı önizleyin (Araç kapalı olmalıdır.) - - - Reset Calibration - Kalibrasyonu sıfırla - - - RESET - SIFIRLA - - - Are you sure you want to reset calibration? - Kalibrasyon ayarını sıfırlamak istediğinizden emin misiniz? - - - Review Training Guide - Eğitim kılavuzunu inceleyin - - - REVIEW - GÖZDEN GEÇİR - - - Review the rules, features, and limitations of openpilot - openpilot sisteminin kurallarını ve sınırlamalarını gözden geçirin. - - - Are you sure you want to review the training guide? - Eğitim kılavuzunu incelemek istediğinizden emin misiniz? - - - Regulatory - Mevzuat - - - VIEW - BAK - - - Change Language - Dili değiştir - - - CHANGE - DEĞİŞTİR - - - Select a language - Dil seçin - - - Reboot - Yeniden başlat - - - Power Off - Sistemi kapat - - - Your device is pointed %1° %2 and %3° %4. - Cihazınız %1° %2 ve %3° %4 yönünde ayarlı - - - down - aşağı - - - up - yukarı - - - left - sol - - - right - sağ - - - Are you sure you want to reboot? - Cihazı Tekrar başlatmak istediğinizden eminmisiniz? - - - Disengage to Reboot - Bağlantıyı kes ve Cihazı Yeniden başlat - - - Are you sure you want to power off? - Cihazı kapatmak istediğizden eminmisiniz? - - - Disengage to Power Off - Bağlantıyı kes ve Cihazı kapat - - - Reset - - - - Review - - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Cihazınızı comma connect (connect.comma.ai) ile eşleştirin ve comma prime aboneliğine göz atın. - - - Pair Device - - - - PAIR - - - - Disengage to Reset Calibration - - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - -Steering lag calibration is %1% complete. - - - - - -Steering lag calibration is complete. - - - - Steering torque response calibration is %1% complete. - - - - Steering torque response calibration is complete. - - - - - DriverViewWindow - - camera starting - kamera başlatılıyor - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - - - - CHILL MODE ON - - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - - - Firehose Mode: ACTIVE - - - - ACTIVE - - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - - - - Firehose Mode - - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - MAX - - - - InputDialog - - Cancel - Kapat - - - Need at least %n character(s)! - - En az %n karakter gerekli! - - - - - MultiOptionDialog - - Select - Seç - - - Cancel - İptal et - - - - Networking - - Advanced - Gelişmiş Seçenekler - - - Enter password - Parolayı girin - - - for "%1" - için "%1" - - - Wrong password - Yalnış parola - - - - OffroadAlert - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - - - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - - - - Unable to download updates -%1 - - - - Taking camera snapshots. System won't start until finished. - - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - - - - Acknowledge Excessive Actuation - - - - Snooze Update - Güncellemeyi sessize al - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - - - - - OffroadHome - - UPDATE - GÜNCELLE - - - ALERTS - UYARILAR - - - ALERT - UYARI - - - - OnroadAlerts - - openpilot Unavailable - - - - TAKE CONTROL IMMEDIATELY - - - - Reboot Device - - - - Waiting to start - - - - System Unresponsive - - - - - PairingPopup - - Pair your device to your comma account - comma.ai hesabınız ile cihazı eşleştirin - - - Go to https://connect.comma.ai on your phone - Telefonuzdan https://connect.comma.ai sitesine gidin - - - Click "add new device" and scan the QR code on the right - Yeni cihaz eklemek için sağdaki QR kodunu okutun - - - Bookmark connect.comma.ai to your home screen to use it like an app - Uygulama gibi kullanmak için connect.comma.ai sitesini yer işaretlerine ekleyin. - - - Please connect to Wi-Fi to complete initial pairing - - - - - ParamControl - - Enable - - - - Cancel - - - - - PrimeAdWidget - - Upgrade Now - Hemen yükselt - - - Become a comma prime member at connect.comma.ai - connect.comma.ai üzerinden comma prime üyesi olun - - - PRIME FEATURES: - PRIME ABONELİĞİNİN ÖZELLİKLERİ: - - - Remote access - Uzaktan erişim - - - 24/7 LTE connectivity - - - - 1 year of drive storage - - - - Remote snapshots - - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ ABONE - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - %n dakika önce - - - - %n hour(s) ago - - %n saat önce - - - - %n day(s) ago - - %n gün önce - - - - now - - - - - SettingsWindow - - × - x - - - Device - Cihaz - - - Network - - - - Toggles - Değiştirme - - - Software - Yazılım - - - Developer - - - - Firehose - - - - - SetupWidget - - Finish Setup - Kurulumu bitir - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Cihazınızı comma connect (connect.comma.ai) ile eşleştirin ve comma prime aboneliğine göz atın. - - - Pair device - Cihazı eşleştirme - - - - Sidebar - - CONNECT - BAĞLANTI - - - OFFLINE - ÇEVRİMDIŞI - - - ONLINE - ÇEVRİMİÇİ - - - ERROR - HATA - - - TEMP - SICAKLIK - - - HIGH - YÜKSEK - - - GOOD - İYİ - - - OK - TAMAM - - - VEHICLE - ARAÇ - - - NO - HAYIR - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-FI - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Uninstall %1 - Kaldır %1 - - - UNINSTALL - KALDIR - - - Are you sure you want to uninstall? - Kaldırmak istediğinden eminmisin? - - - CHECK - KONTROL ET - - - Updates are only downloaded while the car is off. - - - - Current Version - - - - Download - - - - Install Update - - - - INSTALL - - - - Target Branch - - - - SELECT - - - - Select a branch - - - - Uninstall - - - - failed to check for update - - - - DOWNLOAD - - - - update available - - - - never - - - - up to date, last checked %1 - - - - - SshControl - - SSH Keys - SSH Anahtarları - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - UYARI: Bu, GitHub ayarlarınızdaki tüm ortak anahtarlara SSH erişimi sağlar. Asla kendi kullanıcı adınız dışında bir sonraki başlatılışında çekilir. GitHub kullanıcı adı girmeyin. - - - ADD - EKLE - - - Enter your GitHub username - Github kullanıcı adınızı giriniz - - - LOADING - YÜKLENİYOR - - - REMOVE - KALDIR - - - Username '%1' has no keys on GitHub - Kullanısının '%1' Github erişim anahtarı yok - - - Request timed out - İstek zaman aşımına uğradı - - - Username '%1' doesn't exist on GitHub - Github kullanıcısı %1 bulunamadı - - - - SshToggle - - Enable SSH - SSH aç - - - - TermsPage - - Decline - Reddet - - - Agree - Kabul et - - - Welcome to openpilot - - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - - - - - TogglesPanel - - Enable openpilot - openpilot'u aktifleştir - - - Enable Lane Departure Warnings - Şerit ihlali uyarı alın - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - 50 km/s (31 mph) hızın üzerinde sürüş sırasında aracınız dönüş sinyali vermeden algılanan bir sonraki başlatılışında çekilir. şerit çizgisi ihlalinde şeride geri dönmek için uyarılar alın. - - - Use Metric System - Metrik sistemi kullan - - - Display speed in km/h instead of mph. - Hızı mph yerine km/h şeklinde görüntüleyin. - - - Record and Upload Driver Camera - Sürücü kamerasını kayıt et. - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Sürücüye bakan kamera verisini yükleyin ve Cihazın algoritmasını geliştirmemize yardımcı olun. - - - When enabled, pressing the accelerator pedal will disengage openpilot. - Aktifleştirilirse eğer gaz pedalına basınca openpilot devre dışı kalır. - - - Experimental Mode - - - - Disengage on Accelerator Pedal - - - - Aggressive - - - - Standard - - - - Relaxed - - - - Driving Personality - - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - - - - End-to-End Longitudinal Control - - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - - - - New Driving Visualization - - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - - - - openpilot longitudinal control may come in a future update. - - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - - - - Always-On Driver Monitoring - - - - Enable driver monitoring even when openpilot is not engaged. - - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Record and Upload Microphone Audio - - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - WiFiPromptWidget - - Open - - - - Maximize your training data uploads to improve openpilot's driving models. - - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - - WifiUI - - Scanning for networks... - Ağ aranıyor... - - - CONNECTING... - BAĞLANILIYOR... - - - FORGET - UNUT - - - Forget Wi-Fi Network "%1"? - Wi-Fi ağını unut "%1"? - - - Forget - - - - diff --git a/selfdrive/ui/translations/zh-CHS.ts b/selfdrive/ui/translations/zh-CHS.ts deleted file mode 100644 index 9481e62f10..0000000000 --- a/selfdrive/ui/translations/zh-CHS.ts +++ /dev/null @@ -1,1069 +0,0 @@ - - - - - AbstractAlert - - Close - 关闭 - - - Reboot and Update - 重启并更新 - - - - AdvancedNetworking - - Back - 返回 - - - Enable Tethering - 启用WiFi热点 - - - Tethering Password - WiFi热点密码 - - - EDIT - 编辑 - - - Enter new tethering password - 输入新的WiFi热点密码 - - - IP Address - IP 地址 - - - Enable Roaming - 启用数据漫游 - - - APN Setting - APN 设置 - - - Enter APN - 输入 APN - - - leave blank for automatic configuration - 留空以自动配置 - - - Cellular Metered - 按流量计费的手机移动网络 - - - Hidden Network - 隐藏的网络 - - - CONNECT - 连线 - - - Enter SSID - 输入 SSID - - - Enter password - 输入密码 - - - for "%1" - 网络名称:"%1" - - - Prevent large data uploads when on a metered cellular connection - 在按流量计费的移动网络上,防止上传大数据 - - - default - 默认 - - - metered - 按流量计费 - - - unmetered - 不按流量计费 - - - Wi-Fi Network Metered - 按流量计费的 WLAN 网络 - - - Prevent large data uploads when on a metered Wi-Fi connection - 在按流量计费的 WLAN 网络上,防止上传大数据 - - - - ConfirmationDialog - - Ok - 好的 - - - Cancel - 取消 - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - 您必须接受条款和条件以使用openpilot。 - - - Back - 返回 - - - Decline, uninstall %1 - 拒绝并卸载%1 - - - - DeveloperPanel - - Joystick Debug Mode - 摇杆调试模式 - - - Longitudinal Maneuver Mode - 纵向操控测试模式 - - - openpilot Longitudinal Control (Alpha) - openpilot纵向控制(Alpha 版) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - 警告:此车辆的 openpilot 纵向控制功能目前处于Alpha版本,使用此功能将会停用自动紧急制动(AEB)功能。 - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - 在这辆车上,openpilot 默认使用车辆内建的主动巡航控制(ACC),而非 openpilot 的纵向控制。启用此项功能可切换至 openpilot 的纵向控制。当启用 openpilot 纵向控制 Alpha 版本时,建议同时启用实验性模式(Experimental mode)。 - - - Enable ADB - 启用 ADB - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB(Android调试桥接)允许通过USB或网络连接到您的设备。更多信息请参见 [https://docs.comma.ai/how-to/connect-to-comma](https://docs.comma.ai/how-to/connect-to-comma)。 - - - - DevicePanel - - Dongle ID - 设备ID(Dongle ID) - - - N/A - N/A - - - Serial - 序列号 - - - Driver Camera - 驾驶员摄像头 - - - PREVIEW - 预览 - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - 打开并预览驾驶员摄像头,以确保驾驶员监控具有良好视野。(仅熄火时可用) - - - Reset Calibration - 重置设备校准 - - - RESET - 重置 - - - Are you sure you want to reset calibration? - 您确定要重置设备校准吗? - - - Review Training Guide - 新手指南 - - - REVIEW - 查看 - - - Review the rules, features, and limitations of openpilot - 查看 openpilot 的使用规则,以及其功能和限制 - - - Are you sure you want to review the training guide? - 您确定要查看新手指南吗? - - - Regulatory - 监管信息 - - - VIEW - 查看 - - - Change Language - 切换语言 - - - CHANGE - 切换 - - - Select a language - 选择语言 - - - Reboot - 重启 - - - Power Off - 关机 - - - Your device is pointed %1° %2 and %3° %4. - 您的设备校准为%1° %2、%3° %4。 - - - down - 朝下 - - - up - 朝上 - - - left - 朝左 - - - right - 朝右 - - - Are you sure you want to reboot? - 您确定要重新启动吗? - - - Disengage to Reboot - 取消openpilot以重新启动 - - - Are you sure you want to power off? - 您确定要关机吗? - - - Disengage to Power Off - 取消openpilot以关机 - - - Reset - 重置 - - - Review - 预览 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 将您的设备与comma connect (connect.comma.ai)配对并领取您的comma prime优惠。 - - - Pair Device - 配对设备 - - - PAIR - 配对 - - - Disengage to Reset Calibration - 解除以重置校准 - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - openpilot 要求设备的安装角度:左右偏移需在 4° 以内,上下俯仰角度需在向上 5° 至向下 9° 的范围内。 - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - openpilot 会持续进行校准,因此很少需要重置。如果车辆电源已开启,重置校准会重新启动 openpilot。 - - - - -Steering lag calibration is %1% complete. - - -转向延迟校准已完成 %1%。 - - - - -Steering lag calibration is complete. - - -转向延迟校准已完成。 - - - Steering torque response calibration is %1% complete. - 转向扭矩响应校准已完成 %1%。 - - - Steering torque response calibration is complete. - 转向扭矩响应校准已完成。 - - - - DriverViewWindow - - camera starting - 正在启动相机 - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - 试验模式运行 - - - CHILL MODE ON - 轻松模式运行 - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - openpilot 通过观察人类驾驶(包括您)来学习如何驾驶。 - -“Firehose 模式”允许您最大化上传训练数据,以改进 openpilot 的驾驶模型。更多数据意味着更强大的模型,也就意味着更优秀的“实验模式”。 - - - Firehose Mode: ACTIVE - Firehose 模式:激活中 - - - ACTIVE - 激活中 - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - 为了达到最佳效果,请每周将您的设备带回室内,并连接到优质的 USB-C 充电器和 Wi-Fi。<br><br>Firehose 模式在行驶时也能运行,但需连接到移动热点或使用不限流量的 SIM 卡。<br><br><br><b>常见问题</b><br><br><i>我开车的方式或地点有影响吗?</i>不会,请像平常一样驾驶即可。<br><br><i>Firehose 模式会上传所有的驾驶片段吗?</i>不会,我们会选择性地上传部分片段。<br><br><i>什么是好的 USB-C 充电器?</i>任何快速手机或笔记本电脑充电器都应该适用。<br><br><i>我使用的软件版本有影响吗?</i>有的,只有官方 openpilot(以及特定的分支)可以用于训练。 - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>目前已有 %n 段</b> 您的驾驶数据被纳入训练数据集。 - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>闲置</span>:请连接到不限流量的网络 - - - Firehose Mode - Firehose 模式 - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - 最高定速 - - - - InputDialog - - Cancel - 取消 - - - Need at least %n character(s)! - - 至少需要 %n 个字符! - - - - - MultiOptionDialog - - Select - 选择 - - - Cancel - 取消 - - - - Networking - - Advanced - 高级 - - - Enter password - 输入密码 - - - for "%1" - 网络名称:"%1" - - - Wrong password - 密码错误 - - - - OffroadAlert - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - 请立即连接网络检查更新。如果不连接网络,openpilot 将在 %1 后便无法使用 - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - 请连接至互联网以检查更新。在连接至互联网并完成更新检查之前,openpilot 将不会自动启动。 - - - Unable to download updates -%1 - 无法下载更新 -%1 - - - Taking camera snapshots. System won't start until finished. - 正在使用相机拍摄中。在完成之前,系统将无法启动。 - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - 一个针对您设备的操作系统更新正在后台下载中。当更新准备好安装时,您将收到提示进行更新。 - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot 无法识别您的车辆。您的车辆可能未被支持,或是其电控单元 (ECU) 未被识别。请提交一个 Pull Request 为您的车辆添加正确的固件版本。需要帮助吗?请加入 discord.comma.ai。 - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot 检测到设备的安装位置发生变化。请确保设备完全安装在支架上,并确保支架牢固地固定在挡风玻璃上。 - - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - 设备温度过高。系统正在冷却中,等冷却完毕后才会启动。目前内部组件温度:%1 - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - 设备未能注册到 comma.ai 后端。该设备将无法连接或上传数据到 comma.ai 服务器,也无法获得 comma.ai 的支持。如果该设备是在 comma.ai/shop 购买的,请访问 https://comma.ai/support 提交工单。 - - - Acknowledge Excessive Actuation - 确认过度作动 - - - Snooze Update - 推迟更新 - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - openpilot 在您上一次驾驶中,检测到过度的 %1 作动。请访问 https://comma.ai/support 联系客服,并提供您设备的 Dongle ID 以便进行故障排查。 - - - - OffroadHome - - UPDATE - 更新 - - - ALERTS - 警报 - - - ALERT - 警报 - - - - OnroadAlerts - - openpilot Unavailable - 无法使用 openpilot - - - TAKE CONTROL IMMEDIATELY - 立即接管 - - - Reboot Device - 重启设备 - - - Waiting to start - 等待开始 - - - System Unresponsive - 系统无响应 - - - - PairingPopup - - Pair your device to your comma account - 将您的设备与comma账号配对 - - - Go to https://connect.comma.ai on your phone - 在手机上访问 https://connect.comma.ai - - - Click "add new device" and scan the QR code on the right - 点击“添加新设备”,扫描右侧二维码 - - - Bookmark connect.comma.ai to your home screen to use it like an app - 将 connect.comma.ai 收藏到您的主屏幕,以便像应用程序一样使用它 - - - Please connect to Wi-Fi to complete initial pairing - 请连接 Wi-Fi 以完成初始配对 - - - - ParamControl - - Cancel - 取消 - - - Enable - 启用 - - - - PrimeAdWidget - - Upgrade Now - 现在升级 - - - Become a comma prime member at connect.comma.ai - 打开connect.comma.ai以注册comma prime会员 - - - PRIME FEATURES: - comma prime特权: - - - Remote access - 远程访问 - - - 24/7 LTE connectivity - 全天候 LTE 连接 - - - 1 year of drive storage - 一年的行驶记录储存空间 - - - Remote snapshots - 远程快照 - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ 已订阅 - - - comma prime - comma prime - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - %n 分钟前 - - - - %n hour(s) ago - - %n 小时前 - - - - %n day(s) ago - - %n 天前 - - - - now - 现在 - - - - SettingsWindow - - × - × - - - Device - 设备 - - - Network - 网络 - - - Toggles - 设定 - - - Software - 软件 - - - Developer - 开发人员 - - - Firehose - Firehose - - - - SetupWidget - - Finish Setup - 完成设置 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 将您的设备与comma connect (connect.comma.ai)配对并领取您的comma prime优惠。 - - - Pair device - 配对设备 - - - - Sidebar - - CONNECT - CONNECT - - - OFFLINE - 离线 - - - ONLINE - 在线 - - - ERROR - 连接出错 - - - TEMP - 设备温度 - - - HIGH - 过热 - - - GOOD - 良好 - - - OK - 一般 - - - VEHICLE - 车辆连接 - - - NO - - - - PANDA - PANDA - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - 以太网 - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - 车辆熄火时才能下载升级文件。 - - - Current Version - 当前版本 - - - Download - 下载 - - - Install Update - 安装更新 - - - INSTALL - 安装 - - - Target Branch - 目标分支 - - - SELECT - 选择 - - - Select a branch - 选择分支 - - - UNINSTALL - 卸载 - - - Uninstall %1 - 卸载 %1 - - - Are you sure you want to uninstall? - 您确定要卸载吗? - - - CHECK - 查看 - - - Uninstall - 卸载 - - - failed to check for update - 检查更新失败 - - - up to date, last checked %1 - 已经是最新版本,上次检查时间为 %1 - - - DOWNLOAD - 下载 - - - update available - 有可用的更新 - - - never - 从未更新 - - - - SshControl - - SSH Keys - SSH密钥 - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - 警告:这将授予SSH访问权限给您GitHub设置中的所有公钥。切勿输入您自己以外的GitHub用户名。comma员工永远不会要求您添加他们的GitHub用户名。 - - - ADD - 添加 - - - Enter your GitHub username - 输入您的GitHub用户名 - - - LOADING - 正在加载 - - - REMOVE - 删除 - - - Username '%1' has no keys on GitHub - 用户名“%1”在GitHub上没有密钥 - - - Request timed out - 请求超时 - - - Username '%1' doesn't exist on GitHub - GitHub上不存在用户名“%1” - - - - SshToggle - - Enable SSH - 启用SSH - - - - TermsPage - - Decline - 拒绝 - - - Agree - 同意 - - - Welcome to openpilot - 欢迎使用 openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - 您必须接受《条款与条件》才能使用 openpilot。在继续之前,请先阅读最新条款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。 - - - - TogglesPanel - - Enable openpilot - 启用openpilot - - - Enable Lane Departure Warnings - 启用车道偏离警告 - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - 车速超过31mph(50km/h)时,若检测到车辆越过车道线且未打转向灯,系统将发出警告以提醒您返回车道。 - - - Use Metric System - 使用公制单位 - - - Display speed in km/h instead of mph. - 显示车速时,以km/h代替mph。 - - - Record and Upload Driver Camera - 录制并上传驾驶员摄像头 - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - 上传驾驶员摄像头的数据,帮助改进驾驶员监控算法。 - - - Disengage on Accelerator Pedal - 踩油门时取消控制 - - - When enabled, pressing the accelerator pedal will disengage openpilot. - 启用后,踩下油门踏板将取消openpilot。 - - - Experimental Mode - 测试模式 - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - 允许驾驶模型控制加速和制动,openpilot将模仿人类驾驶车辆,包括在红灯和停车让行标识前停车。鉴于驾驶模型确定行驶车速,所设定的车速仅作为上限。此功能尚处于早期测试状态,有可能会出现操作错误。 - - - New Driving Visualization - 新驾驶视角 - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - 由于此车辆使用自带的ACC纵向控制,当前无法使用试验模式。 - - - openpilot longitudinal control may come in a future update. - openpilot纵向控制可能会在未来的更新中提供。 - - - Aggressive - 积极 - - - Standard - 标准 - - - Relaxed - 舒适 - - - Driving Personality - 驾驶风格 - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 在正式(release)版本以外的分支上,可以测试 openpilot 纵向控制的 Alpha 版本以及实验模式。 - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - 启用 openpilot 纵向控制(alpha)开关以允许实验模式。 - - - End-to-End Longitudinal Control - 端到端纵向控制 - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 推荐使用标准模式。在积极模式下,openpilot 会更靠近前方车辆,并在油门和刹车方面更加激进。在放松模式下,openpilot 会与前方车辆保持更远距离。在支持的车型上,你可以使用方向盘上的距离按钮来循环切换这些驾驶风格。 - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - 在低速时,驾驶可视化将转换为道路朝向的广角摄像头,以更好地展示某些转弯。测试模式标志也将显示在右上角。 - - - Always-On Driver Monitoring - 驾驶员监控常开 - - - Enable driver monitoring even when openpilot is not engaged. - 即使在openpilot未激活时也启用驾驶员监控。 - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - openpilot 系统提供“自适应巡航”和“车道保持”驾驶辅助功能。使用此功能时,您需要时刻保持专注。 - - - Changing this setting will restart openpilot if the car is powered on. - 如果车辆已通电,更改此设置将会重新启动 openpilot。 - - - Record and Upload Microphone Audio - 录制并上传麦克风音频 - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - 在驾驶时录制并存储麦克风音频。该音频将会包含在 comma connect 的行车记录仪视频中。 - - - - WiFiPromptWidget - - Open - 开启 - - - Maximize your training data uploads to improve openpilot's driving models. - 最大化您的训练数据上传,以改善 openpilot 的驾驶模型。 - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose 模式 <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - 正在扫描网络…… - - - CONNECTING... - 正在连接…… - - - FORGET - 忽略 - - - Forget Wi-Fi Network "%1"? - 忽略WiFi网络 "%1"? - - - Forget - 忽略 - - - diff --git a/selfdrive/ui/translations/zh-CHT.ts b/selfdrive/ui/translations/zh-CHT.ts deleted file mode 100644 index c3ef55d3d9..0000000000 --- a/selfdrive/ui/translations/zh-CHT.ts +++ /dev/null @@ -1,1069 +0,0 @@ - - - - - AbstractAlert - - Close - 關閉 - - - Reboot and Update - 重啟並更新 - - - - AdvancedNetworking - - Back - 回上頁 - - - Enable Tethering - 啟用網路分享 - - - Tethering Password - 網路分享密碼 - - - EDIT - 編輯 - - - Enter new tethering password - 輸入新的網路分享密碼 - - - IP Address - IP 地址 - - - Enable Roaming - 啟用漫遊 - - - APN Setting - APN 設置 - - - Enter APN - 輸入 APN - - - leave blank for automatic configuration - 留空白將自動配置 - - - Cellular Metered - 計費的行動網路 - - - Hidden Network - 隱藏的網路 - - - CONNECT - 連線 - - - Enter SSID - 輸入 SSID - - - Enter password - 輸入密碼 - - - for "%1" - 給 "%1" - - - Prevent large data uploads when on a metered cellular connection - 在使用計費行動網路時,防止上傳大量數據 - - - default - 預設 - - - metered - 計費 - - - unmetered - 非計費 - - - Wi-Fi Network Metered - 計費 Wi-Fi 網路 - - - Prevent large data uploads when on a metered Wi-Fi connection - 在使用計費 Wi-Fi 網路時,防止上傳大量數據 - - - - ConfirmationDialog - - Ok - 確定 - - - Cancel - 取消 - - - - DeclinePage - - You must accept the Terms and Conditions in order to use openpilot. - 您必須先接受條款和條件才能使用 openpilot。 - - - Back - 回上頁 - - - Decline, uninstall %1 - 拒絕並解除安裝 %1 - - - - DeveloperPanel - - Joystick Debug Mode - 搖桿調試模式 - - - Longitudinal Maneuver Mode - 縱向操控測試模式 - - - openpilot Longitudinal Control (Alpha) - openpilot 縱向控制 (Alpha 版) - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - 警告:此車輛的 openpilot 縱向控制功能目前處於 Alpha 版本,使用此功能將會停用自動緊急煞車(AEB)功能。 - - - On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - 在這輛車上,openpilot 預設使用車輛內建的主動巡航控制(ACC),而非 openpilot 的縱向控制。啟用此項功能可切換至 openpilot 的縱向控制。當啟用 openpilot 縱向控制 Alpha 版本時,建議同時啟用實驗性模式(Experimental mode)。 - - - Enable ADB - 啟用 ADB - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - ADB(Android 調試橋接)允許通過 USB 或網絡連接到您的設備。更多信息請參見 [https://docs.comma.ai/how-to/connect-to-comma](https://docs.comma.ai/how-to/connect-to-comma)。 - - - - DevicePanel - - Dongle ID - Dongle ID - - - N/A - 無法使用 - - - Serial - 序號 - - - Driver Camera - 駕駛員監控鏡頭 - - - PREVIEW - 預覽 - - - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - 預覽駕駛員監控鏡頭畫面,以確保其具有良好視野。(僅在熄火時可用) - - - Reset Calibration - 重設校準 - - - RESET - 重設 - - - Are you sure you want to reset calibration? - 您確定要重設校準嗎? - - - Review Training Guide - 觀看使用教學 - - - REVIEW - 觀看 - - - Review the rules, features, and limitations of openpilot - 觀看 openpilot 的使用規則、功能和限制 - - - Are you sure you want to review the training guide? - 您確定要觀看使用教學嗎? - - - Regulatory - 法規/監管 - - - VIEW - 觀看 - - - Change Language - 更改語言 - - - CHANGE - 更改 - - - Select a language - 選擇語言 - - - Reboot - 重新啟動 - - - Power Off - 關機 - - - Your device is pointed %1° %2 and %3° %4. - 你的裝置目前朝%2 %1° 以及朝%4 %3° 。 - - - down - - - - up - - - - left - - - - right - - - - Are you sure you want to reboot? - 您確定要重新啟動嗎? - - - Disengage to Reboot - 請先取消控車才能重新啟動 - - - Are you sure you want to power off? - 您確定您要關機嗎? - - - Disengage to Power Off - 請先取消控車才能關機 - - - Reset - 重設 - - - Review - 回顧 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 將您的裝置與 comma connect (connect.comma.ai) 配對並領取您的 comma 高級會員優惠。 - - - Pair Device - 配對裝置 - - - PAIR - 配對 - - - Disengage to Reset Calibration - 解除以重設校準 - - - openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - openpilot 要求裝置的安裝角度,左右偏移須在 4° 以內,上下角度則須介於仰角 5° 至俯角 9° 之間。 - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - openpilot 會持續進行校準,因此很少需要重設。若車輛電源開啟,重設校準將會重新啟動 openpilot。 - - - - -Steering lag calibration is %1% complete. - - -轉向延遲校準已完成 %1%。 - - - - -Steering lag calibration is complete. - - -轉向延遲校準已完成。 - - - Steering torque response calibration is %1% complete. - 轉向扭矩反應校準已完成 %1%。 - - - Steering torque response calibration is complete. - 轉向扭矩反應校準已完成。 - - - - DriverViewWindow - - camera starting - 開啟相機中 - - - - ExperimentalModeButton - - EXPERIMENTAL MODE ON - 實驗模式 ON - - - CHILL MODE ON - 輕鬆模式 ON - - - - FirehosePanel - - openpilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - openpilot 透過觀察人類駕駛(包括您)來學習如何駕駛。 - -「Firehose 模式」可讓您最大化上傳訓練數據,以改進 openpilot 的駕駛模型。更多數據代表更強大的模型,也就意味著更優秀的「實驗模式」。 - - - Firehose Mode: ACTIVE - Firehose 模式:啟用中 - - - ACTIVE - 啟用中 - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. - 為了達到最佳效果,請每週將您的裝置帶回室內,並連接至優質的 USB-C 充電器與 Wi-Fi。<br><br>訓練資料上傳模式在行駛時也能運作,但需連接至行動熱點或使用不限流量的 SIM 卡。<br><br><br><b>常見問題</b><br><br><i>我開車的方式或地點有影響嗎?</i> 不會,請像平常一樣駕駛即可。<br><br><i>Firehose 模式會上傳所有的駕駛片段嗎?</i>不會,我們會選擇性地上傳部分片段。<br><br><i>什麼是好的 USB-C 充電器?</i>任何快速手機或筆電充電器都應該適用。<br><br><i>我使用的軟體版本有影響嗎?</i>有的,只有官方 openpilot(以及特定的分支)可以用於訓練。 - - - <b>%n segment(s)</b> of your driving is in the training dataset so far. - - <b>目前已有 %n 段</b> 您的駕駛數據被納入訓練資料集。 - - - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>閒置中</span>:請連接到不按流量計費的網絡 - - - Firehose Mode - Firehose 模式 - - - - HudRenderer - - km/h - km/h - - - mph - mph - - - MAX - 最高 - - - - InputDialog - - Cancel - 取消 - - - Need at least %n character(s)! - - 需要至少 %n 個字元! - - - - - MultiOptionDialog - - Select - 選擇 - - - Cancel - 取消 - - - - Networking - - Advanced - 進階 - - - Enter password - 輸入密碼 - - - for "%1" - 給 "%1" - - - Wrong password - 密碼錯誤 - - - - OffroadAlert - - Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - 請立即連接網路檢查更新。如果不連接網路,openpilot 將在 %1 後便無法使用 - - - Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - 請連接至網際網路以檢查更新。在連接至網際網路並完成更新檢查之前,openpilot 將不會自動啟動。 - - - Unable to download updates -%1 - 無法下載更新 -%1 - - - Taking camera snapshots. System won't start until finished. - 正在使用相機拍攝中。在完成之前,系統將無法啟動。 - - - An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - 一個有關操作系統的更新正在後台下載中。當更新準備好安裝時,您將收到提示進行更新。 - - - openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot 無法識別您的車輛。您的車輛可能未被支援,或是其電控單元 (ECU) 未被識別。請提交一個 Pull Request 為您的車輛添加正確的韌體版本。需要幫助嗎?請加入 discord.comma.ai 。 - - - openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot 偵測到裝置的安裝位置發生變化。請確保裝置完全安裝在支架上,並確保支架牢固地固定在擋風玻璃上。 - - - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - 裝置溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1 - - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - 裝置註冊 comma.ai 後端失敗。此裝置將無法連線或上傳資料至 comma.ai 伺服器,也無法獲得 comma.ai 的支援。若此裝置購自 comma.ai/shop,請至 https://comma.ai/support 建立支援請求。 - - - Acknowledge Excessive Actuation - 確認過度作動 - - - Snooze Update - 延後更新 - - - openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting. - openpilot 在您上次的駕駛中,偵測到過度的 %1 作動。請至 https://comma.ai/support 聯絡客服,並提供您裝置的 Dongle ID 以進行故障排除。 - - - - OffroadHome - - UPDATE - 更新 - - - ALERTS - 提醒 - - - ALERT - 提醒 - - - - OnroadAlerts - - openpilot Unavailable - 無法使用 openpilot - - - TAKE CONTROL IMMEDIATELY - 立即接管 - - - Reboot Device - 請重新啟裝置 - - - Waiting to start - 等待開始 - - - System Unresponsive - 系統無回應 - - - - PairingPopup - - Pair your device to your comma account - 將裝置與您的 comma 帳號配對 - - - Go to https://connect.comma.ai on your phone - 用手機連至 https://connect.comma.ai - - - Click "add new device" and scan the QR code on the right - 點選 "add new device" 後掃描右邊的二維碼 - - - Bookmark connect.comma.ai to your home screen to use it like an app - 將 connect.comma.ai 加入您的主螢幕,以便像手機 App 一樣使用它 - - - Please connect to Wi-Fi to complete initial pairing - 請連接 Wi-Fi 以完成初始配對 - - - - ParamControl - - Cancel - 取消 - - - Enable - 啟用 - - - - PrimeAdWidget - - Upgrade Now - 馬上升級 - - - Become a comma prime member at connect.comma.ai - 成為 connect.comma.ai 的高級會員 - - - PRIME FEATURES: - 高級會員特點: - - - Remote access - 遠端存取 - - - 24/7 LTE connectivity - 24/7 LTE 連線 - - - 1 year of drive storage - 一年的行駛記錄儲存空間 - - - Remote snapshots - 遠端快照 - - - - PrimeUserWidget - - ✓ SUBSCRIBED - ✓ 已訂閱 - - - comma prime - comma 高級會員 - - - - QObject - - openpilot - openpilot - - - %n minute(s) ago - - %n 分鐘前 - - - - %n hour(s) ago - - %n 小時前 - - - - %n day(s) ago - - %n 天前 - - - - now - 現在 - - - - SettingsWindow - - × - × - - - Device - 裝置 - - - Network - 網路 - - - Toggles - 設定 - - - Software - 軟體 - - - Developer - 開發人員 - - - Firehose - Firehose - - - - SetupWidget - - Finish Setup - 完成設置 - - - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 將您的裝置與 comma connect (connect.comma.ai) 配對並領取您的 comma 高級會員優惠。 - - - Pair device - 配對裝置 - - - - Sidebar - - CONNECT - 雲端服務 - - - OFFLINE - 已離線 - - - ONLINE - 已連線 - - - ERROR - 錯誤 - - - TEMP - 溫度 - - - HIGH - 偏高 - - - GOOD - 正常 - - - OK - 一般 - - - VEHICLE - 車輛通訊 - - - NO - 未連線 - - - PANDA - 車輛通訊 - - - -- - -- - - - Wi-Fi - Wi-Fi - - - ETH - ETH - - - 2G - 2G - - - 3G - 3G - - - LTE - LTE - - - 5G - 5G - - - - SoftwarePanel - - Updates are only downloaded while the car is off. - 系統更新只會在熄火時下載。 - - - Current Version - 當前版本 - - - Download - 下載 - - - Install Update - 安裝更新 - - - INSTALL - 安裝 - - - Target Branch - 目標分支 - - - SELECT - 選取 - - - Select a branch - 選取一個分支 - - - UNINSTALL - 解除安裝 - - - Uninstall %1 - 解除安裝 %1 - - - Are you sure you want to uninstall? - 您確定您要解除安裝嗎? - - - CHECK - 檢查 - - - Uninstall - 解除安裝 - - - failed to check for update - 檢查更新失敗 - - - up to date, last checked %1 - 已經是最新版本,上次檢查時間為 %1 - - - DOWNLOAD - 下載 - - - update available - 有可用的更新 - - - never - 從未更新 - - - - SshControl - - SSH Keys - SSH 金鑰 - - - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - 警告:這將授權給 GitHub 帳號中所有公鑰 SSH 訪問權限。切勿輸入非您自己的 GitHub 使用者名稱。comma 員工「永遠不會」要求您添加他們的 GitHub 使用者名稱。 - - - ADD - 新增 - - - Enter your GitHub username - 請輸入您 GitHub 的使用者名稱 - - - LOADING - 載入中 - - - REMOVE - 移除 - - - Username '%1' has no keys on GitHub - GitHub 用戶 '%1' 沒有設定任何金鑰 - - - Request timed out - 請求超時 - - - Username '%1' doesn't exist on GitHub - GitHub 用戶 '%1' 不存在 - - - - SshToggle - - Enable SSH - 啟用 SSH 服務 - - - - TermsPage - - Decline - 拒絕 - - - Agree - 接受 - - - Welcome to openpilot - 歡迎使用 openpilot - - - You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - 您必須接受《條款與條件》才能使用 openpilot。在繼續之前,請先閱讀最新條款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。 - - - - TogglesPanel - - Enable openpilot - 啟用 openpilot - - - Enable Lane Departure Warnings - 啟用車道偏離警告 - - - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - 車速在時速 50 公里 (31 英里) 以上且未打方向燈的情況下,如果偵測到車輛駛出目前車道線時,發出車道偏離警告。 - - - Use Metric System - 使用公制單位 - - - Display speed in km/h instead of mph. - 啟用後,速度單位顯示將從 mp/h 改為 km/h。 - - - Record and Upload Driver Camera - 記錄並上傳駕駛監控影像 - - - Upload data from the driver facing camera and help improve the driver monitoring algorithm. - 上傳駕駛監控的錄影來協助我們提升駕駛監控的準確率。 - - - Disengage on Accelerator Pedal - 油門取消控車 - - - When enabled, pressing the accelerator pedal will disengage openpilot. - 啟用後,踩踏油門將會取消 openpilot 控制。 - - - Experimental Mode - 實驗模式 - - - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - 讓駕駛模型來控制油門及煞車。openpilot將會模擬人類的駕駛行為,包含在看見紅燈及停止標示時停車。由於車速將由駕駛模型決定,因此您設定的時速將成為速度上限。本功能仍在早期實驗階段,請預期模型有犯錯的可能性。 - - - New Driving Visualization - 新的駕駛視覺介面 - - - Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - 因車輛使用內建ACC系統,無法在本車輛上啟動實驗模式。 - - - openpilot longitudinal control may come in a future update. - openpilot 縱向控制可能會在未來的更新中提供。 - - - Aggressive - 積極 - - - Standard - 標準 - - - Relaxed - 舒適 - - - Driving Personality - 駕駛風格 - - - An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 在正式 (release) 版以外的分支上可以測試 openpilot 縱向控制的 Alpha 版本以及實驗模式。 - - - Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - 啟用 openpilot 縱向控制(alpha)切換以允許實驗模式。 - - - End-to-End Longitudinal Control - 端到端縱向控制 - - - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 建議使用標準模式。在積極模式下,openpilot 會更接近前車並更積極地使用油門和剎車。在輕鬆模式下,openpilot 會與前車保持較遠距離。對於支援的汽車,您可以使用方向盤上的距離按鈕來切換這些駕駛風格。 - - - The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - 在低速時,駕駛可視化將切換至道路朝向的廣角攝影機,以更好地顯示某些彎道。在右上角還會顯示「實驗模式」的標誌。 - - - Always-On Driver Monitoring - 駕駛監控常開 - - - Enable driver monitoring even when openpilot is not engaged. - 即使在openpilot未激活時也啟用駕駛監控。 - - - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - openpilot 系統提供「主動式巡航」與「車道維持」等駕駛輔助功能。使用這些功能時,您必須隨時保持專注。 - - - Changing this setting will restart openpilot if the car is powered on. - 若車輛電源為開啟狀態,變更此設定將會重新啟動 openpilot。 - - - Record and Upload Microphone Audio - 錄製並上傳麥克風音訊 - - - Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - 在駕駛時錄製並儲存麥克風音訊。此音訊將會收錄在 comma connect 的行車記錄器影片中。 - - - - WiFiPromptWidget - - Open - 開啟 - - - Maximize your training data uploads to improve openpilot's driving models. - 最大化您的訓練數據上傳,以改善 openpilot 的駕駛模型。 - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose 模式 <span style='font-family: Noto Color Emoji;'>🔥</span> - - - - WifiUI - - Scanning for networks... - 掃描無線網路中... - - - CONNECTING... - 連線中... - - - FORGET - 清除 - - - Forget Wi-Fi Network "%1"? - 清除 Wi-Fi 網路 "%1"? - - - Forget - 清除 - - - diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc deleted file mode 100644 index ed851a41c8..0000000000 --- a/selfdrive/ui/ui.cc +++ /dev/null @@ -1,199 +0,0 @@ -#include "selfdrive/ui/ui.h" - -#include -#include - -#include - -#include "common/transformations/orientation.hpp" -#include "common/swaglog.h" -#include "common/util.h" -#include "system/hardware/hw.h" - -#define BACKLIGHT_DT 0.05 -#define BACKLIGHT_TS 10.00 - -static void update_sockets(UIState *s) { - s->sm->update(0); -} - -static void update_state(UIState *s) { - SubMaster &sm = *(s->sm); - UIScene &scene = s->scene; - - if (sm.updated("liveCalibration")) { - auto list2rot = [](const capnp::List::Reader &rpy_list) ->Eigen::Matrix3f { - return euler2rot({rpy_list[0], rpy_list[1], rpy_list[2]}).cast(); - }; - - auto live_calib = sm["liveCalibration"].getLiveCalibration(); - if (live_calib.getCalStatus() == cereal::LiveCalibrationData::Status::CALIBRATED) { - auto device_from_calib = list2rot(live_calib.getRpyCalib()); - auto wide_from_device = list2rot(live_calib.getWideFromDeviceEuler()); - s->scene.view_from_calib = VIEW_FROM_DEVICE * device_from_calib; - s->scene.view_from_wide_calib = VIEW_FROM_DEVICE * wide_from_device * device_from_calib; - } else { - s->scene.view_from_calib = s->scene.view_from_wide_calib = VIEW_FROM_DEVICE; - } - } - if (sm.updated("pandaStates")) { - auto pandaStates = sm["pandaStates"].getPandaStates(); - if (pandaStates.size() > 0) { - scene.pandaType = pandaStates[0].getPandaType(); - - if (scene.pandaType != cereal::PandaState::PandaType::UNKNOWN) { - scene.ignition = false; - for (const auto& pandaState : pandaStates) { - scene.ignition |= pandaState.getIgnitionLine() || pandaState.getIgnitionCan(); - } - } - } - } else if ((s->sm->frame - s->sm->rcv_frame("pandaStates")) > 5*UI_FREQ) { - scene.pandaType = cereal::PandaState::PandaType::UNKNOWN; - } - if (sm.updated("wideRoadCameraState")) { - auto cam_state = sm["wideRoadCameraState"].getWideRoadCameraState(); - scene.light_sensor = std::max(100.0f - cam_state.getExposureValPercent(), 0.0f); - } else if (!sm.allAliveAndValid({"wideRoadCameraState"})) { - scene.light_sensor = -1; - } - scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; - - auto params = Params(); - scene.recording_audio = params.getBool("RecordAudio") && scene.started; -} - -void ui_update_params(UIState *s) { - auto params = Params(); - s->scene.is_metric = params.getBool("IsMetric"); -} - -void UIState::updateStatus() { - if (scene.started && sm->updated("selfdriveState")) { - auto ss = (*sm)["selfdriveState"].getSelfdriveState(); - auto state = ss.getState(); - if (state == cereal::SelfdriveState::OpenpilotState::PRE_ENABLED || state == cereal::SelfdriveState::OpenpilotState::OVERRIDING) { - status = STATUS_OVERRIDE; - } else { - status = ss.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED; - } - } - - if (engaged() != engaged_prev) { - engaged_prev = engaged(); - emit engagedChanged(engaged()); - } - - // Handle onroad/offroad transition - if (scene.started != started_prev || sm->frame == 1) { - if (scene.started) { - status = STATUS_DISENGAGED; - scene.started_frame = sm->frame; - } - started_prev = scene.started; - emit offroadTransition(!scene.started); - } -} - -UIState::UIState(QObject *parent) : QObject(parent) { - sm = std::make_unique(std::vector{ - "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", - "pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2", - "wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan", - }); - prime_state = new PrimeState(this); - language = QString::fromStdString(Params().get("LanguageSetting")); - - // update timer - timer = new QTimer(this); - QObject::connect(timer, &QTimer::timeout, this, &UIState::update); - timer->start(1000 / UI_FREQ); -} - -void UIState::update() { - update_sockets(this); - update_state(this); - updateStatus(); - - emit uiUpdate(*this); -} - -Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) { - setAwake(true); - resetInteractiveTimeout(); - - QObject::connect(uiState(), &UIState::uiUpdate, this, &Device::update); -} - -void Device::update(const UIState &s) { - updateBrightness(s); - updateWakefulness(s); -} - -void Device::setAwake(bool on) { - if (on != awake) { - awake = on; - Hardware::set_display_power(awake); - LOGD("setting display power %d", awake); - emit displayPowerChanged(awake); - } -} - -void Device::resetInteractiveTimeout(int timeout) { - if (timeout == -1) { - timeout = (ignition_on ? 10 : 30); - } - interactive_timeout = timeout * UI_FREQ; -} - -void Device::updateBrightness(const UIState &s) { - float clipped_brightness = offroad_brightness; - if (s.scene.started && s.scene.light_sensor >= 0) { - clipped_brightness = s.scene.light_sensor; - - // CIE 1931 - https://www.photonstophotos.net/GeneralTopics/Exposure/Psychometric_Lightness_and_Gamma.htm - if (clipped_brightness <= 8) { - clipped_brightness = (clipped_brightness / 903.3); - } else { - clipped_brightness = std::pow((clipped_brightness + 16.0) / 116.0, 3.0); - } - - // Scale back to 10% to 100% - clipped_brightness = std::clamp(100.0f * clipped_brightness, 10.0f, 100.0f); - } - - int brightness = brightness_filter.update(clipped_brightness); - if (!awake) { - brightness = 0; - } - - if (brightness != last_brightness) { - if (!brightness_future.isRunning()) { - brightness_future = QtConcurrent::run(Hardware::set_brightness, brightness); - last_brightness = brightness; - } - } -} - -void Device::updateWakefulness(const UIState &s) { - bool ignition_just_turned_off = !s.scene.ignition && ignition_on; - ignition_on = s.scene.ignition; - - if (ignition_just_turned_off) { - resetInteractiveTimeout(); - } else if (interactive_timeout > 0 && --interactive_timeout == 0) { - emit interactiveTimeout(); - } - - setAwake(s.scene.ignition || interactive_timeout > 0); -} - -UIState *uiState() { - static UIState ui_state; - return &ui_state; -} - -Device *device() { - static Device _device; - return &_device; -} diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h deleted file mode 100644 index b3c482aafe..0000000000 --- a/selfdrive/ui/ui.h +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include - -#include "cereal/messaging/messaging.h" -#include "common/mat.h" -#include "common/params.h" -#include "common/util.h" -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/prime_state.h" - -const int UI_BORDER_SIZE = 30; -const int UI_HEADER_HEIGHT = 420; - -const int UI_FREQ = 20; // Hz -const int BACKLIGHT_OFFROAD = 50; - -const Eigen::Matrix3f VIEW_FROM_DEVICE = (Eigen::Matrix3f() << - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0, - 1.0, 0.0, 0.0).finished(); - -const Eigen::Matrix3f FCAM_INTRINSIC_MATRIX = (Eigen::Matrix3f() << - 2648.0, 0.0, 1928.0 / 2, - 0.0, 2648.0, 1208.0 / 2, - 0.0, 0.0, 1.0).finished(); - -// tici ecam focal probably wrong? magnification is not consistent across frame -// Need to retrain model before this can be changed -const Eigen::Matrix3f ECAM_INTRINSIC_MATRIX = (Eigen::Matrix3f() << - 567.0, 0.0, 1928.0 / 2, - 0.0, 567.0, 1208.0 / 2, - 0.0, 0.0, 1.0).finished(); - -typedef enum UIStatus { - STATUS_DISENGAGED, - STATUS_OVERRIDE, - STATUS_ENGAGED, -} UIStatus; - -const QColor bg_colors [] = { - [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8), - [STATUS_OVERRIDE] = QColor(0x91, 0x9b, 0x95, 0xf1), - [STATUS_ENGAGED] = QColor(0x17, 0x86, 0x44, 0xf1), -}; - -typedef struct UIScene { - Eigen::Matrix3f view_from_calib = VIEW_FROM_DEVICE; - Eigen::Matrix3f view_from_wide_calib = VIEW_FROM_DEVICE; - cereal::PandaState::PandaType pandaType; - - cereal::LongitudinalPersonality personality; - - float light_sensor = -1; - bool started, ignition, is_metric, recording_audio; - uint64_t started_frame; -} UIScene; - -class UIState : public QObject { - Q_OBJECT - -public: - UIState(QObject* parent = 0); - void updateStatus(); - inline bool engaged() const { - return scene.started && (*sm)["selfdriveState"].getSelfdriveState().getEnabled(); - } - - std::unique_ptr sm; - UIStatus status; - UIScene scene = {}; - QString language; - PrimeState *prime_state; - -signals: - void uiUpdate(const UIState &s); - void offroadTransition(bool offroad); - void engagedChanged(bool engaged); - -private slots: - void update(); - -private: - QTimer *timer; - bool started_prev = false; - bool engaged_prev = false; -}; - -UIState *uiState(); - -// device management class -class Device : public QObject { - Q_OBJECT - -public: - Device(QObject *parent = 0); - bool isAwake() { return awake; } - void setOffroadBrightness(int brightness) { - offroad_brightness = std::clamp(brightness, 0, 100); - } - -private: - bool awake = false; - int interactive_timeout = 0; - bool ignition_on = false; - - int offroad_brightness = BACKLIGHT_OFFROAD; - int last_brightness = 0; - FirstOrderFilter brightness_filter; - QFuture brightness_future; - - void updateBrightness(const UIState &s); - void updateWakefulness(const UIState &s); - void setAwake(bool on); - -signals: - void displayPowerChanged(bool on); - void interactiveTimeout(); - -public slots: - void resetInteractiveTimeout(int timeout = -1); - void update(const UIState &s); -}; - -Device *device(); -void ui_update_params(UIState *s); diff --git a/selfdrive/ui/update_translations.py b/selfdrive/ui/update_translations.py index 643d246012..e91820f242 100755 --- a/selfdrive/ui/update_translations.py +++ b/selfdrive/ui/update_translations.py @@ -1,48 +1,38 @@ #!/usr/bin/env python3 -import argparse -import json +from itertools import chain import os - -from openpilot.common.basedir import BASEDIR -from openpilot.system.ui.lib.multilang import UI_DIR, TRANSLATIONS_DIR, LANGUAGES_FILE - -TRANSLATIONS_INCLUDE_FILE = os.path.join(TRANSLATIONS_DIR, "alerts_generated.h") -PLURAL_ONLY = ["en"] # base language, only create entries for strings with plural forms - - -def generate_translations_include(): - # offroad alerts - # TODO translate events from openpilot.selfdrive/controls/lib/events.py - content = "// THIS IS AN AUTOGENERATED FILE, PLEASE EDIT alerts_offroad.json\n" - with open(os.path.join(BASEDIR, "selfdrive/selfdrived/alerts_offroad.json")) as f: - for alert in json.load(f).values(): - content += f'QT_TRANSLATE_NOOP("OffroadAlert", R"({alert["text"]})");\n' - - with open(TRANSLATIONS_INCLUDE_FILE, "w") as f: - f.write(content) - - -def update_translations(vanish: bool = False, translation_files: None | list[str] = None, translations_dir: str = TRANSLATIONS_DIR): - if translation_files is None: - with open(LANGUAGES_FILE) as f: - translation_files = json.load(f).values() - - for file in translation_files: - tr_file = os.path.join(translations_dir, f"{file}.ts") - args = f"lupdate -locations none -recursive {UI_DIR} -ts {tr_file} -I {BASEDIR}" - if vanish: - args += " -no-obsolete" - if file in PLURAL_ONLY: - args += " -pluralonly" - ret = os.system(args) - assert ret == 0 +from openpilot.system.ui.lib.multilang import SYSTEM_UI_DIR, UI_DIR, TRANSLATIONS_DIR, multilang + + +def update_translations(): + files = [] + for root, _, filenames in chain(os.walk(SYSTEM_UI_DIR), + os.walk(os.path.join(UI_DIR, "widgets")), + os.walk(os.path.join(UI_DIR, "layouts")), + os.walk(os.path.join(UI_DIR, "onroad"))): + for filename in filenames: + if filename.endswith(".py"): + files.append(os.path.join(root, filename)) + + # Create main translation file + cmd = ("xgettext -L Python --keyword=tr --keyword=trn:1,2 --keyword=tr_noop --from-code=UTF-8 " + + "--flag=tr:1:python-brace-format --flag=trn:1:python-brace-format --flag=trn:2:python-brace-format " + + "-o translations/app.pot {}").format(" ".join(files)) + + ret = os.system(cmd) + assert ret == 0 + + # Generate/update translation files for each language + for name in multilang.languages.values(): + if os.path.exists(os.path.join(TRANSLATIONS_DIR, f"app_{name}.po")): + cmd = f"msgmerge --update --no-fuzzy-matching --backup=none --sort-output translations/app_{name}.po translations/app.pot" + ret = os.system(cmd) + assert ret == 0 + else: + cmd = f"msginit -l {name} --no-translator --input translations/app.pot --output-file translations/app_{name}.po" + ret = os.system(cmd) + assert ret == 0 if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Update translation files for UI", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument("--vanish", action="store_true", help="Remove translations with source text no longer found") - args = parser.parse_args() - - generate_translations_include() - update_translations(args.vanish) + update_translations() diff --git a/selfdrive/ui/update_translations_raylib.py b/selfdrive/ui/update_translations_raylib.py deleted file mode 100755 index e91820f242..0000000000 --- a/selfdrive/ui/update_translations_raylib.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -from itertools import chain -import os -from openpilot.system.ui.lib.multilang import SYSTEM_UI_DIR, UI_DIR, TRANSLATIONS_DIR, multilang - - -def update_translations(): - files = [] - for root, _, filenames in chain(os.walk(SYSTEM_UI_DIR), - os.walk(os.path.join(UI_DIR, "widgets")), - os.walk(os.path.join(UI_DIR, "layouts")), - os.walk(os.path.join(UI_DIR, "onroad"))): - for filename in filenames: - if filename.endswith(".py"): - files.append(os.path.join(root, filename)) - - # Create main translation file - cmd = ("xgettext -L Python --keyword=tr --keyword=trn:1,2 --keyword=tr_noop --from-code=UTF-8 " + - "--flag=tr:1:python-brace-format --flag=trn:1:python-brace-format --flag=trn:2:python-brace-format " + - "-o translations/app.pot {}").format(" ".join(files)) - - ret = os.system(cmd) - assert ret == 0 - - # Generate/update translation files for each language - for name in multilang.languages.values(): - if os.path.exists(os.path.join(TRANSLATIONS_DIR, f"app_{name}.po")): - cmd = f"msgmerge --update --no-fuzzy-matching --backup=none --sort-output translations/app_{name}.po translations/app.pot" - ret = os.system(cmd) - assert ret == 0 - else: - cmd = f"msginit -l {name} --no-translator --input translations/app.pot --output-file translations/app_{name}.po" - ret = os.system(cmd) - assert ret == 0 - - -if __name__ == "__main__": - update_translations() diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 5c02227ca5..940e7f9125 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -80,7 +80,6 @@ procs = [ PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(WEBCAM or not PC)), PythonProcess("sensord", "system.sensord.sensord", only_onroad, enabled=not PC), - # NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, enabled=False), PythonProcess("ui", "selfdrive.ui.ui", always_run), PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad), PythonProcess("locationd", "selfdrive.locationd.locationd", only_onroad), diff --git a/third_party/qt5/larch64/bin/lrelease b/third_party/qt5/larch64/bin/lrelease deleted file mode 100755 index 5891f85851..0000000000 --- a/third_party/qt5/larch64/bin/lrelease +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:56ddfc4ead01eaf43cba41e2095ec4f52309c53a60ba9e351d8dbd900151228f -size 546824 diff --git a/third_party/qt5/larch64/bin/lupdate b/third_party/qt5/larch64/bin/lupdate deleted file mode 100755 index 0055aae229..0000000000 --- a/third_party/qt5/larch64/bin/lupdate +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7af679aa708031f6d19baabbd48e92d23462c6ff287caccdcb5c6324168d985d -size 1095744 diff --git a/tools/cabana/utils/api.cc b/tools/cabana/utils/api.cc index 99e904c490..2ed461fdf6 100644 --- a/tools/cabana/utils/api.cc +++ b/tools/cabana/utils/api.cc @@ -1,4 +1,4 @@ -#include "selfdrive/ui/qt/api.h" +#include "tools/cabana/utils/api.h" #include #include @@ -13,9 +13,10 @@ #include #include +#include "common/params.h" #include "common/util.h" #include "system/hardware/hw.h" -#include "selfdrive/ui/qt/util.h" +#include "tools/cabana/utils/util.h" QString getVersion() { static QString version = QString::fromStdString(Params().get("Version"));