mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-31 22:25:08 +00:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5d2b9557e7 | ||
|
891da46c3c | ||
|
e9bc90d91a | ||
|
921d0ee884 | ||
|
3e8948339d | ||
|
e56f73da83 | ||
|
c250d2c674 | ||
|
c15469f477 | ||
|
73f15149b6 | ||
|
118a35c304 | ||
|
acb869b21c | ||
|
71706879d0 | ||
|
f5b3523ec6 | ||
|
8639938584 | ||
|
011ee20fbb | ||
|
763859d478 | ||
|
c19019a500 | ||
|
b1a2257d4d | ||
|
32d6a346ab | ||
|
2616a7a529 | ||
|
f16a770fee | ||
|
45e84ce23e | ||
|
9e5c9ca11a | ||
|
f9e74caa50 | ||
|
6feb8f478c | ||
|
2e38789836 | ||
|
1f106ee9f1 | ||
|
86e3faf75a | ||
|
9379d89d03 | ||
|
90787911fa | ||
|
8b8106bad8 | ||
|
b20ccf16bd | ||
|
b4f8f1befa | ||
|
6adb73bf5e |
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.kde.kdeconnect_tp"
|
||||
android:versionCode="12401"
|
||||
android:versionName="1.24.1">
|
||||
android:versionCode="12405"
|
||||
android:versionName="1.24.5">
|
||||
|
||||
<supports-screens
|
||||
android:anyDensity="true"
|
||||
@@ -59,7 +59,8 @@
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:theme="@style/KdeConnectTheme.NoActionBar"
|
||||
android:name="org.kde.kdeconnect.MyApplication">
|
||||
android:name="org.kde.kdeconnect.MyApplication"
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
|
||||
<receiver
|
||||
android:name="com.android.mms.transaction.PushReceiver"
|
||||
@@ -274,9 +275,10 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.kde.kdeconnect.Plugins.MousePadPlugin.ComposeSendActivity"
|
||||
android:label="Compose send"
|
||||
android:label="@string/compose_send_title"
|
||||
android:exported="false"
|
||||
android:parentActivityName="org.kde.kdeconnect.Plugins.MousePadPlugin.MousePadActivity">
|
||||
android:parentActivityName="org.kde.kdeconnect.Plugins.MousePadPlugin.MousePadActivity"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.kde.kdeconnect.Plugins.MousePadPlugin.MousePadActivity" />
|
||||
@@ -364,6 +366,7 @@
|
||||
<action android:name="android.service.chooser.ChooserTargetService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<!--
|
||||
<service
|
||||
android:name="org.kde.kdeconnect.Plugins.MouseReceiverPlugin.MouseReceiverService"
|
||||
android:exported="true"
|
||||
@@ -375,6 +378,7 @@
|
||||
android:name="android.accessibilityservice"
|
||||
android:resource="@xml/mouse_receiver_service" />
|
||||
</service>
|
||||
-->
|
||||
|
||||
<activity
|
||||
android:name="org.kde.kdeconnect.Plugins.NotificationsPlugin.NotificationFilterActivity"
|
||||
|
15
build.gradle
15
build.gradle
@@ -6,7 +6,7 @@ import com.github.jk1.license.render.TextReportRenderer
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.8.10'
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'com.android.tools.build:gradle:8.0.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
namespace 'org.kde.kdeconnect_tp'
|
||||
compileSdkVersion 33
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
@@ -28,7 +29,13 @@ android {
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
compose true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.2"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
@@ -138,6 +145,12 @@ ext {
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
|
||||
implementation 'androidx.compose.material3:material3:1.0.1'
|
||||
implementation 'androidx.compose.ui:ui-tooling-preview:1.4.2'
|
||||
implementation 'androidx.activity:activity-compose:1.7.1'
|
||||
implementation 'com.google.accompanist:accompanist-themeadapter-material3:0.31.0-alpha'
|
||||
implementation 'androidx.constraintlayout:constraintlayout-compose:1.0.1'
|
||||
|
||||
implementation 'androidx.media:media:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.core:core-ktx:1.10.0'
|
||||
|
@@ -1,3 +1,6 @@
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.enableJetifier=false
|
||||
android.nonFinalResIds=false
|
||||
android.nonTransitiveRClass=false
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
|
||||
|
@@ -18,7 +18,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: dummy:1
|
||||
msgid "Integrate Android with the KDE Plasma Desktop."
|
||||
|
@@ -3,7 +3,7 @@ msgstr ""
|
||||
"Project-Id-Version: kdeorg\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2019-06-30 11:38+0200\n"
|
||||
"PO-Revision-Date: 2023-04-10 14:10\n"
|
||||
"PO-Revision-Date: 2023-04-16 12:31\n"
|
||||
"Last-Translator: Albert Vaca Cintora <albertvaka@gmail.com>\n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Language: zh_CN\n"
|
||||
|
@@ -16,7 +16,8 @@
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
tools:context="org.kde.kdeconnect.UserInterface.MainActivity">
|
||||
tools:context="org.kde.kdeconnect.UserInterface.MainActivity"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />
|
||||
|
||||
|
@@ -5,7 +5,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="org.kde.kdeconnect.UserInterface.About.AboutKDEActivity">
|
||||
tools:context="org.kde.kdeconnect.UserInterface.About.AboutKDEActivity"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />
|
||||
|
||||
|
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/compose"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:ems="10"
|
||||
android:hint="@string/click_here_to_type"
|
||||
android:imeActionLabel="@string/send_compose"
|
||||
android:imeOptions="actionSend|actionDone"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textLongMessage|textMultiLine"
|
||||
android:isScrollContainer="true"
|
||||
android:saveEnabled="true"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout2"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
tools:ignore="SpeakableTextPresentCheck,TextContrastCheck" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@@ -6,7 +6,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="org.kde.kdeconnect.UserInterface.CustomDevicesActivity">
|
||||
tools:context="org.kde.kdeconnect.UserInterface.CustomDevicesActivity"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />
|
||||
|
||||
|
@@ -4,6 +4,7 @@
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="org.kde.kdeconnect.UserInterface.About.LicensesActivity">
|
||||
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />
|
||||
|
@@ -7,14 +7,14 @@
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"> <!-- fitSystemWindows to make the drawer slide below the Lollipop transparent status bar -->
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
tools:context="org.kde.kdeconnect.UserInterface.MainActivity">
|
||||
tools:context="org.kde.kdeconnect.UserInterface.MainActivity"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout"/>
|
||||
|
||||
|
@@ -9,9 +9,7 @@
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="8dp"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.ActionBar">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
@@ -21,10 +19,7 @@
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/mpris_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/toolbar_color"
|
||||
app:tabIndicatorColor="?android:textColorPrimary"
|
||||
app:tabSelectedTextColor="?android:textColorPrimary" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
@@ -6,7 +6,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="org.kde.kdeconnect.UserInterface.PluginSettingsActivity">
|
||||
tools:context="org.kde.kdeconnect.UserInterface.PluginSettingsActivity"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />
|
||||
|
||||
|
@@ -5,12 +5,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.ActionBar">
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:elevation="8dp"
|
||||
app:title="@string/kde_connect"/>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:kdeconnect="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_send_compose"
|
||||
android:icon="@android:drawable/ic_menu_send"
|
||||
android:title="@string/send_compose"
|
||||
kdeconnect:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/menu_clear_compose"
|
||||
android:title="@string/clear_compose"
|
||||
kdeconnect:showAsAction="always" />
|
||||
|
||||
</menu>
|
@@ -6,13 +6,13 @@
|
||||
android:id="@+id/menu_rise_up"
|
||||
android:icon="@drawable/ic_arrow_upward_black_24dp"
|
||||
android:title="@string/rise_up"
|
||||
android:iconTint="@color/text_color"
|
||||
kdeconnect:iconTint="?colorOnSurfaceVariant"
|
||||
kdeconnect:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_rise_down"
|
||||
android:icon="@drawable/ic_arrow_downward_black_24dp"
|
||||
android:title="@string/rise_down"
|
||||
android:iconTint="@color/text_color"
|
||||
kdeconnect:iconTint="?colorOnSurfaceVariant"
|
||||
kdeconnect:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">Uzaq klaviatura bağlantısını aktiv edin</string>
|
||||
<string name="remotekeyboard_multiple_connections">Birdən çox uzaq klaviatura bağlantısı var, tənzimləmək üçün cihazı seçin</string>
|
||||
<string name="open_mousepad">Məsafədən giriş</string>
|
||||
<string name="mousepad_info">Siçan kursorunu hərəkət etdirmək üçün barmağı ekranda sürüşdürün. Klik üçün ekrana vurun, sağ və orta siçan düymələri üçün iki/üç barmaqla toxunuş edin. Sürüşdürmək üçün iki barmaqdan istifadə edin. Hiroskop siçan funksionallığı plaqin ayarlarında aktiv edilməlidir</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Qoşulmuş cihaz üçün klaviatura ilə daxiletmə dəstəklənmir</string>
|
||||
<string name="mousepad_single_tap_settings_title">Bir barmaq toxunuşu əməlini təyin edin</string>
|
||||
<string name="mousepad_double_tap_settings_title">İki barmaq toxunuşu əməlini təyin edin</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Üç barmaq toxunuşu əməlini təyin edin</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Toxunma panelinin həsassləğını təyin edin</string>
|
||||
<string name="mousepad_mouse_buttons_title">Siçan düymələrini göstərmək</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Kursorun sürətini təyin edin</string>
|
||||
<string name="mousepad_scroll_direction_title">Sürüşdürmənin əks istiqaməti</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
@@ -216,8 +218,11 @@
|
||||
<string name="sftp_action_mode_menu_delete">Silmək</string>
|
||||
<string name="sftp_no_storage_locations_configured">Saxlama yeri tənzimlənməyib</string>
|
||||
<string name="sftp_saf_permission_explanation">Fayllara uzaqdan daxil olmaq üçün saxlama yerlərini konfiqurasiya etməlisiniz</string>
|
||||
<string name="sftp_manage_storage_permission_explanation">Bu cihazdakı fayllara giriş əldə etmək üçün KDE Connect-ə yaddaşı idarə etməyə icazə vermək lazımdır.</string>
|
||||
<string name="no_players_connected">Pleyer tapılmadı</string>
|
||||
<string name="send_files">Faylları göndərmək</string>
|
||||
<string name="block_notification_contents">Bildirilərin tərkiblərini kilidləmək</string>
|
||||
<string name="block_notification_images">Bildiriş şəlkillərini kilidləmək</string>
|
||||
<string name="pairing_title">KDE Connect Cihazları</string>
|
||||
<string name="pairing_description">Eyni şəbəkədəki KDE Connect işləyən digər cihazlar burada görünməlidir</string>
|
||||
<string name="device_rename_title">Cihazın adını dəyişmək</string>
|
||||
@@ -240,8 +245,10 @@
|
||||
<string name="close">Bağlamaq</string>
|
||||
<string name="plugins_need_permission">Bəzi qoşmaların işləməsi üçün icazələr lazımdır (daha çox məlumat üçün toxunun):</string>
|
||||
<string name="permission_explanation">Bu qoşmanın işləməsi üçün icazələr lazımdır</string>
|
||||
<string name="all_permissions_granted">Bütün icazələr verildi 🎉</string>
|
||||
<string name="optional_permission_explanation">Bütün funksiyaların işləməsi üçün əlavə icazələr verməlisiniz</string>
|
||||
<string name="plugins_need_optional_permission">Bəzi qoşmalarda icazə çatışmamazlığı səbəbindən bir sıra imkanlar söndürülmüşdür (daha çox məlumat üçün toxunun)</string>
|
||||
<string name="share_optional_permission_explanation">Faylları qəbul etmək üçün yaddaşa girişə icazə verilməlidirü</string>
|
||||
<string name="telepathy_permission_explanation">İş Masanızdan telefonunuzdakı SMS\'ləri oxumaq və SMS göndərmək üçün SMS\'ə girişə icazə verməlisiniz</string>
|
||||
<string name="telephony_permission_explanation">İş Masanızda telefon zənglərini görmək üçün Zəng Tarixçəsinə və Zəng yığımı vəziyyətinə icazə verməlisiniz</string>
|
||||
<string name="telephony_optional_permission_explanation">Telefon nömrəsi əvəzinə əlaqənin adını görmək üçün Əlaqə Kitabçasına girişə icazə verməlisiniz</string>
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">Отдалечената връзка с клавиатурата е активна</string>
|
||||
<string name="remotekeyboard_multiple_connections">Има повече от една отдалечена връзка за клавиатура, изберете устройството за конфигуриране</string>
|
||||
<string name="open_mousepad">Отдалечен вход</string>
|
||||
<string name="mousepad_info">Преместете пръст на екрана, за да преместите курсора на мишката. Докоснете за щракване и използвайте два/три пръста за десни и средни бутони. Използвайте 2 пръста за превъртане.Използвайте дълго натискане за влачене. Функцията на жироскопската мишка може да бъде активирана в настройките на плъгина</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Въвеждането от клавиатурата не се поддържа от сдвоеното устройство</string>
|
||||
<string name="mousepad_single_tap_settings_title">Задаване на действие с натискане с един пръст</string>
|
||||
<string name="mousepad_double_tap_settings_title">Задаване на действие за докосване с два пръста</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Задаване на действие с докосване с три пръста</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Настройка на чувствителността на тъчпада</string>
|
||||
<string name="mousepad_mouse_buttons_title">Показване на бутони на мишката</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Задаване на ускорение на показалеца</string>
|
||||
<string name="mousepad_scroll_direction_title">Обръщане на посоката на превъртане</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">Vzdálené připojení klávesnice je aktivní</string>
|
||||
<string name="remotekeyboard_multiple_connections">Je k dispozici více než jedno připojení klávesnice. Vyberte zařízení pro jeho nastavení.</string>
|
||||
<string name="open_mousepad">Vzdálený vstup</string>
|
||||
<string name="mousepad_info">Pohybujte prstem po obrazovce pro pohybování kurzorem myši. Ťukněte pro kliknutí a použijte dva/tři prsty jako pravé a prostřední tlačítko. Použijte 2 prsty pro posunování. Pro přetažení dlouze podržte. Funkčnost gyro myš lze povolit v předvolbách modulu.</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Vstup pomocí klávesnice není spárovaným zařízením podporován</string>
|
||||
<string name="mousepad_single_tap_settings_title">Nastavit činnost pro ťuknutí prstem</string>
|
||||
<string name="mousepad_double_tap_settings_title">Nastavit činnost pro ťuknutí dvěma prsty</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Nastavit činnost pro ťuknutí třemi prsty</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Nastavit citlivost touchpadu</string>
|
||||
<string name="mousepad_mouse_buttons_title">Zobrazit tlačítka myši</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Nastavit akceleraci ukazatele</string>
|
||||
<string name="mousepad_scroll_direction_title">Obrácený směr posunu</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">Remote keyboard connection is active</string>
|
||||
<string name="remotekeyboard_multiple_connections">There is more than one remote keyboard connection, select the device to configure</string>
|
||||
<string name="open_mousepad">Remote input</string>
|
||||
<string name="mousepad_info">Move a finger on the screen to move the mouse cursor. Tap for a click, and use two/three fingers for right and middle buttons. Use 2 fingers to scroll. Use a long press to drag and drop. Gyro mouse functionality can be enabled from plugin preferences</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Keyboard input not supported by the paired device</string>
|
||||
<string name="mousepad_single_tap_settings_title">Set one finger tap action</string>
|
||||
<string name="mousepad_double_tap_settings_title">Set two finger tap action</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Set three finger tap action</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Set touchpad sensitivity</string>
|
||||
<string name="mousepad_mouse_buttons_title">Show mouse buttons</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Set pointer acceleration</string>
|
||||
<string name="mousepad_scroll_direction_title">Reverse Scrolling Direction</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">La conexión remota de teclado está activa</string>
|
||||
<string name="remotekeyboard_multiple_connections">Hay más de una conexión remota de teclado, seleccione el dispositivo a configurar</string>
|
||||
<string name="open_mousepad">Entrada remota</string>
|
||||
<string name="mousepad_info">Mueva un dedo sobre la pantalla para mover el cursor del ratón. Pulse para ejecutar un clic y use dos/tres dedos para emular los botones derecho y central. Use 2 dedos para desplazar las pantalla. Use una pulsación larga para arrastrar y soltar. La funcionalidad de la rueda del ratón puede ser activada desde las preferencias del complemento.</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Entrada de teclado no soportada por el dispositivo vinculado.</string>
|
||||
<string name="mousepad_single_tap_settings_title">Establecer la acción al pulsar con un dedo</string>
|
||||
<string name="mousepad_double_tap_settings_title">Establecer la acción al pulsar con dos dedos</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Establecer la acción al pulsar con tres dedos</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Establecer sensibilidad del panel táctil</string>
|
||||
<string name="mousepad_mouse_buttons_title">Mostrar botones del ratón</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Establecer la aceleración del puntero</string>
|
||||
<string name="mousepad_scroll_direction_title">Invertir dirección de desplazamiento</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -180,7 +180,7 @@
|
||||
</string-array>
|
||||
<string name="mpris_notification_settings_title">Erakutsi euskarri kontrolaren jakinarazpena</string>
|
||||
<string name="mpris_notification_settings_summary">Utzi zure euskarri-jotzaileak kontrolatzen KDE Connect ireki gabe</string>
|
||||
<string name="share_to">Partekatu honi...</string>
|
||||
<string name="share_to">Partekatu honekin...</string>
|
||||
<string name="protocol_version_newer">Gailu honek protokoloaren bertsio berriago bat erabiltzen du</string>
|
||||
<string name="plugin_settings_with_name">%s ezarpenak</string>
|
||||
<string name="invalid_device_name">Gailuaren izen baliogabea</string>
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">Etänäppäimistöyhteys on käytössä</string>
|
||||
<string name="remotekeyboard_multiple_connections">Etänäppäimistöyhteyksiä on useampia: valitse asetettava laite</string>
|
||||
<string name="open_mousepad">Kauko-ohjaus</string>
|
||||
<string name="mousepad_info">Siirrä hiirikohdistinta liikuttamalla sormea näytöllä. Tee hiirenpainallus napauttamalla, ja käytä kahta tai kolmea sormea oikealle ja keskipainikkeelle. Vieritä kahdella sormella. Pitkällä painalluksella voit vetää ja pudottaa. Gyrohiiritoiminnon voi ottaa käyttää liitännäisen asetuksista</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Paritettu laite ei tue näppäimistösyötettä</string>
|
||||
<string name="mousepad_single_tap_settings_title">Aseta yhden sormen napautuksen toiminto</string>
|
||||
<string name="mousepad_double_tap_settings_title">Aseta kahden sormen napautuksen toiminto</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Aseta kolmen sormen napautuksen toiminto</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Aseta kosketuslevyn herkkyys</string>
|
||||
<string name="mousepad_mouse_buttons_title">Näytä hiiripainikkeet</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Aseta osoittimen kiihdytys</string>
|
||||
<string name="mousepad_scroll_direction_title">Käänteinen vierityssuunta</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
@@ -243,6 +245,7 @@
|
||||
<string name="close">Sulje</string>
|
||||
<string name="plugins_need_permission">Jotkin liitännäiset vaativat toimiakseen lisäkäyttöoikeuksia (lisätietoa napsauttamalla):</string>
|
||||
<string name="permission_explanation">Liitännäinen tarvitsee toimiakseen lisäkäyttöoikeuksia</string>
|
||||
<string name="all_permissions_granted">Kaikki oikeudet myönnetty 🎉</string>
|
||||
<string name="optional_permission_explanation">Kaikkien toimintojen käyttämiseksi sinun on annettava lisäkäyttöoikeuksia</string>
|
||||
<string name="plugins_need_optional_permission">Jotkin liitännäisten ominaisuudet eivät ole käytössä puuttuvien käyttöoikeuksien takia (lisätietoa napsauttamalla):</string>
|
||||
<string name="share_optional_permission_explanation">Talletustilan käyttö on sallittava tiedostojen vastaanottamiseksi</string>
|
||||
|
@@ -51,6 +51,7 @@
|
||||
<string name="remotekeyboard_connected">La connexion au clavier sans fil est active</string>
|
||||
<string name="remotekeyboard_multiple_connections">Plusieurs connexions à des claviers sans fil sont disponibles, sélectionnez le périphérique à configurer</string>
|
||||
<string name="open_mousepad">Contrôle distant</string>
|
||||
<string name="mousepad_info">Faites glisser votre doigt sur l\'écran pour déplacer le pointeur de la souris. Tapotez pour cliquer et utilisez deux / trois doigts pour les clics droit et centre. Utilisez 2 doigts pour faire un défilement. Faites un appui prolongé pour réaliser un glisser-déposer. La fonctionnalité de gyroscope de souris peut être activée à partir des préférences de module externe.</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">La saisie par le clavier n\'est pas pris en charge par le périphérique appairée.</string>
|
||||
<string name="mousepad_single_tap_settings_title">Définir une action pour tapotage avec un doigt</string>
|
||||
<string name="mousepad_double_tap_settings_title">Action pour l\'appui à deux doigts</string>
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">A conexión de teclado remoto está activa.</string>
|
||||
<string name="remotekeyboard_multiple_connections">Hai máis dunha conexión de teclado remoto, seleccione o dispositivo para configurar.</string>
|
||||
<string name="open_mousepad">Entrada remota</string>
|
||||
<string name="mousepad_info">Mova un dedo na pantalla para mover o cursor do rato. Toque para facer clic, e use dous ou tres dedos para os botóns secundario e central. Use dous dedos para desprazar. Prema durante un tempo para arrastrar e soltar. A funcionalidade de rato de xiroscopio pode activarse desde a configuración do complemento.</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">O dispositivo emparellado non permite entrada de teclado</string>
|
||||
<string name="mousepad_single_tap_settings_title">Definir a acción de tocar cun dedo</string>
|
||||
<string name="mousepad_double_tap_settings_title">Definir a acción de tocar con dous dedos</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Definir a acción de tocar con tres dedos</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Definir a sensibilidade do punteiro táctil</string>
|
||||
<string name="mousepad_mouse_buttons_title">Mostrar os botóns do rato</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Definir a aceleración do punteiro</string>
|
||||
<string name="mousepad_scroll_direction_title">Inverter a dirección de desprazamento</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">La connessione della tastiera remota è attiva</string>
|
||||
<string name="remotekeyboard_multiple_connections">Ci sono più connessioni di tastiere remote, seleziona il dispositivo da configurare</string>
|
||||
<string name="open_mousepad">Impulso remoto</string>
|
||||
<string name="mousepad_info">Muovi un dito sullo schermo per spostare il puntatore del mouse. Tocca per un clic e usa due/tre dita per i pulsanti destro e centrale. Utilizza 2 dita per scorrere. Utilizza una pressione lunga per trascinare e rilasciare. È possibile abilitare la funzionalità del mouse giroscopico dalle preferenze dell\'estensione</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Immissione da tastiera non supportata dal dispositivo associato</string>
|
||||
<string name="mousepad_single_tap_settings_title">Imposta azione per il tocco a un dito</string>
|
||||
<string name="mousepad_double_tap_settings_title">Imposta azione per il tocco a due dita</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Imposta azione per il tocco a tre dita</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Imposta la sensibilità del touchpad</string>
|
||||
<string name="mousepad_mouse_buttons_title">Mostra i pulsanti del mouse</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Imposta accelerazione del puntatore</string>
|
||||
<string name="mousepad_scroll_direction_title">Inverti direzione di scorrimento</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">원격 키보드 연결이 활성화됨</string>
|
||||
<string name="remotekeyboard_multiple_connections">원격 키보드 연결이 여러 개 있습니다. 설정할 장치를 선택하십시오</string>
|
||||
<string name="open_mousepad">원격 입력</string>
|
||||
<string name="mousepad_info">화면에서 손가락을 움직이면 마우스 커서를 움직입니다. 화면을 누르면 왼쪽 단추를 누르고, 두 손가락과 세 손가락으로 누르면 오른쪽/가운데 단추를 누릅니다. 두 손가락을 사용하여 스크롤할 수 있습니다. 드래그 앤 드롭을 사용하려면 길게 누르십시오. 플러그인 설정에서 자이로 마우스를 활성화할 수 있습니다</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">페어링된 장치에서 키보드 입력을 지원하지 않음</string>
|
||||
<string name="mousepad_single_tap_settings_title">한 손가락으로 눌렀을 때 동작 설정</string>
|
||||
<string name="mousepad_double_tap_settings_title">두 손가락으로 눌렀을 때 동작 설정</string>
|
||||
<string name="mousepad_triple_tap_settings_title">세 손가락으로 눌렀을 때 동작 설정</string>
|
||||
<string name="mousepad_sensitivity_settings_title">터치패드 감도 설정</string>
|
||||
<string name="mousepad_mouse_buttons_title">마우스 단추 표시</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">포인터 가속 설정</string>
|
||||
<string name="mousepad_scroll_direction_title">스크롤 방향 뒤집기</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
@@ -208,8 +210,11 @@
|
||||
<string name="sftp_action_mode_menu_delete">삭제</string>
|
||||
<string name="sftp_no_storage_locations_configured">저장소 위치가 설정되지 않았음</string>
|
||||
<string name="sftp_saf_permission_explanation">원격으로 파일에 접근하려면 저장소 위치를 설정해야 함</string>
|
||||
<string name="sftp_manage_storage_permission_explanation">이 장치에 있는 파일에 원격 접근을 허용하려면 KDE Connect에서 저장소를 관리할 수 있도록 허용해야 합니다.</string>
|
||||
<string name="no_players_connected">재생기를 찾을 수 없음</string>
|
||||
<string name="send_files">파일 보내기</string>
|
||||
<string name="block_notification_contents">알림 내용 숨기기</string>
|
||||
<string name="block_notification_images">알림 이미지 숨기기</string>
|
||||
<string name="pairing_title">KDE Connect 장치</string>
|
||||
<string name="pairing_description">같은 네트워크에서 KDE Connect를 실행하는 다른 장치가 여기에 표시됩니다.</string>
|
||||
<string name="device_rename_title">장치 이름 바꾸기</string>
|
||||
@@ -232,8 +237,10 @@
|
||||
<string name="close">닫기</string>
|
||||
<string name="plugins_need_permission">권한이 필요한 플러그인(정보를 보려면 누르기):</string>
|
||||
<string name="permission_explanation">이 플러그인을 사용하려면 권한이 필요합니다</string>
|
||||
<string name="all_permissions_granted">모든 권한 허가됨 🎉</string>
|
||||
<string name="optional_permission_explanation">모든 기능을 사용하려면 추가 권한이 필요합니다</string>
|
||||
<string name="plugins_need_optional_permission">일부 플러그인은 권한이 없어서 비활성화되었습니다(정보를 보려면 누르기):</string>
|
||||
<string name="share_optional_permission_explanation">공유된 파일을 받으려면 저장소 접근을 허가해야 합니다</string>
|
||||
<string name="telepathy_permission_explanation">데스크톱에서 문자 메시지를 읽고 보내려면 문자 메시지 접근 권한이 필요합니다</string>
|
||||
<string name="telephony_permission_explanation">데스크톱에서 통화와 문자 메시지를 보려면 통화 기록 및 휴대폰 상태 접근 권한이 필요합니다</string>
|
||||
<string name="telephony_optional_permission_explanation">전화번호 대신 연락처에 등록된 이름을 보려면 주소록 접근 권한이 필요합니다</string>
|
||||
|
@@ -11,7 +11,6 @@
|
||||
<color name="toolbar_color">@android:color/system_neutral1_900</color>
|
||||
<color name="card_stroke_color">@android:color/system_neutral2_800</color>
|
||||
<color name="activity_background">@android:color/system_neutral1_900</color>
|
||||
<item name="lightMode" type="bool">false</item>
|
||||
|
||||
<!-- This is for dark theme. In dark theme both selected and unselected text in the
|
||||
navigation bar should be white. This is different from the light theme as both states have
|
||||
|
@@ -11,7 +11,6 @@
|
||||
<color name="toolbar_color">@android:color/black</color>
|
||||
<color name="card_stroke_color">#8C8C8C</color>
|
||||
<color name="activity_background">@android:color/black</color>
|
||||
<item name="lightMode" type="bool">false</item>
|
||||
|
||||
<!-- This is for dark theme. In dark theme both selected and unselected text in the
|
||||
navigation bar should be white. This is different from the light theme as both states have
|
||||
|
@@ -51,7 +51,6 @@
|
||||
<string name="remotekeyboard_connected">Eksternt tastatursamband er verksamt</string>
|
||||
<string name="remotekeyboard_multiple_connections">Det finst meir enn eitt eksternt tastatursamband (vel eining å setja opp)</string>
|
||||
<string name="open_mousepad">Fjernstyring</string>
|
||||
<string name="mousepad_info">Dra ein finger over skjermen for å flytta peikaren på datamaskina. Trykk for å klikka, og bruk to eller tre fingrar for høvesvis høgre- og midtknappen. Bruk to fingrar for å rulla. Trykk lenge for å dra og sleppa.</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Tekst frå tastaturet er ikkje støtta av den para eininga</string>
|
||||
<string name="mousepad_single_tap_settings_title">Vel handling for éinfingertrykk</string>
|
||||
<string name="mousepad_double_tap_settings_title">Vel handling for tofingertrykk</string>
|
||||
@@ -99,7 +98,6 @@
|
||||
<string name="battery_status_format">Batteri: %d %%</string>
|
||||
<string name="battery_status_low_format">Batteri: %d %% – lågt batterinivå</string>
|
||||
<string name="battery_status_charging_format">Batteri: %d %% – ladar</string>
|
||||
<string name="battery_status_unknown">Batteriinformasjon er ikkje tilgjengeleg</string>
|
||||
<string name="category_connected_devices">Tilkopla einingar</string>
|
||||
<string name="category_not_paired_devices">Tilgjengelege einingar</string>
|
||||
<string name="category_remembered_devices">Hugsa einingar</string>
|
||||
@@ -375,7 +373,6 @@
|
||||
<string name="clear_compose">Tøm</string>
|
||||
<string name="send_compose">Send</string>
|
||||
<string name="open_compose_send">Skriv tekst</string>
|
||||
<string name="app_description">Fleirplattforms-app for kommunikasjon på tvers av einingar (for eksempel mellom telefon og datamaskin)</string>
|
||||
<string name="about_kde_about"><h1>Om</h1> <p>KDE er eit verdsfemnande fellesskap av eldsjeler som programmerer, teiknar, komponerer, dokumenterer, set om eller hjelper til på andre måtar med utvikling av <a href=https://www.gnu.org/philosophy/free-sw.html>fri programvare</a>. Me har laga brukarflata Plasma, hundrevis av program og dei mange programbiblioteka desse byggjer på.</p> <p>KDE er eit fellesskap der inga einskild gruppe, firma eller organisasjon har eigarskap til produkta eller styrer retninga den vidare utviklinga skal gå i. Derimot arbeider me saman om å oppnå vårt felles mål om å laga fri programvare i verdsklasse. Alle er <a href=https://community.kde.org/Get_Involved>velkomne til å bidra</a> – du òg.</p>Du finn meir informasjon om KDE og programma me utviklar på <a href=https://www.kde.org/>https://www.kde.org/</a>.</string>
|
||||
<string name="about_kde_report_bugs_or_wishes"><h1>Meld frå om feil eller ønskje</h1> <p>Ein kan alltid forbetra programvare, og KDE-gruppa arbeider heile tida for det. Men du, som brukar, må melda frå til oss når noko ikkje verkar slik du forventar, eller når noko kunne vore gjort betre.</p> <p>KDE har eit feilsporingssystem. Gå til <a href=https://bugs.kde.org/>https://bugs.kde.org/</a> eller vel «Meld frå om feil» på «Om»-sida for å melda frå om feil.</p> Om du har framlegg til forbetringar, kan du gjerne registrera òg desse i feilsporingssystemet. Sjå då til at du har markert feilrapporten med «Wishlist».</string>
|
||||
<string name="about_kde_join_kde"><h1>Vert med i KDE</h1> <p>Du treng ikkje vera programutviklar for å hjelpa til med KDE. Du kan arbeida med omsetjingar, laga grafikk, tema, lydar eller betre hjelpetekstar. Her er noko for alle!</p> <p>På <a href=https://community.kde.org/Get_Involved>https://community.kde.org/Get_Involved</a> finn du informasjon om nokre prosjekt du kan delta i.</p> Om du vil ha meir informasjon eller dokumentasjon, finn du det du treng på <a href=https://techbase.kde.org/>https://techbase.kde.org/</a>.</string>
|
||||
|
@@ -11,6 +11,5 @@
|
||||
<color name="toolbar_color">@android:color/system_neutral1_50</color>
|
||||
<color name="card_stroke_color">@android:color/system_neutral2_100</color>
|
||||
<color name="activity_background">@android:color/system_neutral1_50</color>
|
||||
<item name="lightMode" type="bool">true</item>
|
||||
</resources>
|
||||
|
||||
|
@@ -51,6 +51,7 @@
|
||||
<string name="remotekeyboard_connected">Połączenie zdalnej klawiatury jest nawiązane</string>
|
||||
<string name="remotekeyboard_multiple_connections">Nawiązano więcej niż jedno połączenie zdalnej klawiatury, wybierz urządzenie do ustawienia</string>
|
||||
<string name="open_mousepad">Zdalne sterowanie</string>
|
||||
<string name="mousepad_info">Przesuwanie palcem po ekranie przesuwa wskaźnik myszy. Stuknięcie jednym, dwoma i trzema palcami wywołuje odpowiednio naciśnięcie lewym, prawym i środkowym przyciskiem myszy. Dwa palce przewijają. Długie naciśnięcie rozpoczyna czynność przeciągania i upuszczania. Zachowania żyroskopowe myszy mogą być włączone z poziomu ustawień wtyczki.</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">Wpisywanie z klawiatury jest nieobsługiwane przez sparowane urządzenie</string>
|
||||
<string name="mousepad_single_tap_settings_title">Ustaw działanie po stuknięciu jednym palcem</string>
|
||||
<string name="mousepad_double_tap_settings_title">Ustaw działanie po stuknięciu dwoma palcami</string>
|
||||
|
@@ -51,11 +51,13 @@
|
||||
<string name="remotekeyboard_connected">A ligação ao teclado remoto está activa</string>
|
||||
<string name="remotekeyboard_multiple_connections">Existe mais que uma ligação a teclados remotos; seleccione o dispositivo a configurar</string>
|
||||
<string name="open_mousepad">Introdução remota de dados</string>
|
||||
<string name="mousepad_info">Mova um dedo pelo ecrã para mover o cursor do rato. Dê um toque para carregar no botão esquerdo e use dois/três dedos para os botões direito e do meio. Use 2 dedos para deslocar-se. Use uma pressão longa para arrastar e largar. A funcionalidade giroscópica do rato pode ser activada a partir das preferências do \'plugin\'</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">O uso do teclado não é suportado pelo dispositivo emparelhado</string>
|
||||
<string name="mousepad_single_tap_settings_title">Definir a acção do toque com um dedo</string>
|
||||
<string name="mousepad_double_tap_settings_title">Definir a acção do toque com dois dedos</string>
|
||||
<string name="mousepad_triple_tap_settings_title">Definir a acção do toque com três dedos</string>
|
||||
<string name="mousepad_sensitivity_settings_title">Definir a sensibilidade do rato por toque</string>
|
||||
<string name="mousepad_mouse_buttons_title">Mostrar os botões do rato</string>
|
||||
<string name="mousepad_acceleration_profile_settings_title">Definir a aceleração do cursor</string>
|
||||
<string name="mousepad_scroll_direction_title">Direcção de Deslocamento Inversa</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
|
@@ -51,6 +51,7 @@
|
||||
<string name="remotekeyboard_connected">தொலை விசைப்பலகை இணைப்பு செயலில் உள்ளது</string>
|
||||
<string name="remotekeyboard_multiple_connections">பல தொலை விசைப்பலகை இணைப்புகள் உள்ளன. அமைக்க வேண்டிய சாதனத்தை தேர்ந்தெடுங்கள்</string>
|
||||
<string name="open_mousepad">தொலை உள்ளீடு</string>
|
||||
<string name="mousepad_info">சுட்டிக்குறியை நகர்த்த ஒரு விரலை திரையில் நகர்த்தவும். \'க்ளிக்\' செய்வதற்கு தட்டுங்கள். வலது/நடு சுட்டி பட்டன்களுக்கு இரண்டு/மூன்று விரல்களை பயன்படுத்தவும். இரண்டு விரல்களைக் கொண்டு உருளவும். இழுத்து போடுவதற்கு நீண்ட அழுத்தத்தை பயன்படுத்தவும். சுழல்காட்டி சுட்டியைபோல் செயல்பட வேண்டுமெனில் செருகுநிரல் அமைப்புகளில் உரிய அம்சத்தை இயக்கலாம்</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">இணைக்கப்பட்டுள்ள சாதனம், விசைப்பலகை உள்ளீட்டை ஆதரிக்காது</string>
|
||||
<string name="mousepad_single_tap_settings_title">ஒருவிரலால் தட்டுவதற்குரிய செயலை அமை</string>
|
||||
<string name="mousepad_double_tap_settings_title">இரண்டு விரல்களால் தட்டுவதற்குரிய செயலை அமை</string>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
<style name="KdeConnectTheme.NoActionBar" parent="KdeConnectThemeBase.NoActionBar">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">@bool/lightMode</item>
|
||||
<item name="android:windowLightStatusBar">?attr/isLightTheme</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="KdeConnectThemeBase.V27" parent="KdeConnectThemeBase">
|
||||
<item name="android:navigationBarColor">@color/activity_background</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowLightNavigationBar">?attr/isLightTheme</item>
|
||||
</style>
|
||||
|
@@ -51,6 +51,7 @@
|
||||
<string name="remotekeyboard_connected">远程键盘连接已启用</string>
|
||||
<string name="remotekeyboard_multiple_connections">发现多个远程键盘连接,请选择要配置的设备</string>
|
||||
<string name="open_mousepad">远程输入</string>
|
||||
<string name="mousepad_info">在屏幕上移动手指来移动光标。轻击代表左键,双指或三指点击代表右键或中键。用双指滚动。用长按来拖放。基于陀螺仪的空中鼠标功能可以在插件的首选项中启用。</string>
|
||||
<string name="mousepad_keyboard_input_not_supported">配对的设备不支持键盘输入</string>
|
||||
<string name="mousepad_single_tap_settings_title">设置单指点击操作</string>
|
||||
<string name="mousepad_double_tap_settings_title">设置双指点击操作</string>
|
||||
|
@@ -11,5 +11,4 @@
|
||||
<color name="toolbar_color">@android:color/white</color>
|
||||
<color name="card_stroke_color">#C8C8C8</color>
|
||||
<color name="activity_background">@android:color/white</color>
|
||||
<item name="lightMode" type="bool">true</item>
|
||||
</resources>
|
@@ -75,6 +75,9 @@
|
||||
<string name="mousepad_scroll_direction" translatable="false">mousepad_scroll_direction</string>
|
||||
<string name="gyro_mouse_enabled" translatable="false">gyro_mouse_enabled</string>
|
||||
<string name="mousepad_mouse_buttons_enabled_pref" translatable="false">mouse_buttons_enabled</string>
|
||||
<string name="gyro_mouse_enabled_title">Enable gyroscope mouse</string>
|
||||
<string name="gyro_mouse_sensitivity_title">Gyroscope sensitivity</string>
|
||||
<string name="gyro_mouse_sensitivity" translatable="false">gyro_mouse_sensitivity</string>
|
||||
<string-array name="mousepad_tap_entries">
|
||||
<item>Left click</item>
|
||||
<item>Right click</item>
|
||||
@@ -485,6 +488,7 @@
|
||||
<string name="click_here_to_type">Tap here to type</string>
|
||||
<string name="clear_compose">Clear</string>
|
||||
<string name="send_compose">Send</string>
|
||||
<string name="compose_send_title">Compose send</string>
|
||||
<string name="open_compose_send">Compose text</string>
|
||||
|
||||
<string name="about_kde_about"><![CDATA[
|
||||
|
@@ -2,25 +2,24 @@
|
||||
<!-- NoActionBar because we use a Toolbar widget as ActionBar -->
|
||||
<style name="KdeConnectThemeBase" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- The main color attributes -->
|
||||
<!-- The three colors used by system widgets, according to https://chris.banes.me/2014/10/17/appcompat-v21/ -->
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primaryDark</item>
|
||||
<item name="colorSecondary">@color/primary</item>
|
||||
<item name="colorOnSecondary">@color/on_secondary</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="colorHighContrast">@color/on_high_contrast</item>
|
||||
<item name="android:windowBackground">@color/activity_background</item>
|
||||
<item name="android:colorBackground">@color/activity_background</item>
|
||||
<!-- TODO: The 2 items below change too much (eg snackbar text is now black, should be white) -->
|
||||
<item name="android:textColorPrimary">@color/text_color_primary</item>
|
||||
<item name="android:textColor">@color/text_color</item>
|
||||
|
||||
<!--For android below 23 api-->
|
||||
<item name="android:statusBarColor">@android:color/black</item>
|
||||
|
||||
<!-- Drawable definitions and overrides -->
|
||||
<item name="divider">?colorHighContrast</item>
|
||||
|
||||
<!-- Style overrides -->
|
||||
<item name="actionModeStyle">@style/ActionModeStyle</item>
|
||||
<item name="toolbarStyle">@style/KdeConnectTheme.Toolbar</item>
|
||||
<item name="actionModeStyle">@style/Widget.Material3.ActionMode</item>
|
||||
<item name="toolbarStyle">@style/Widget.Material3.Toolbar</item>
|
||||
|
||||
<!-- Theme overrides -->
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
|
||||
|
@@ -61,7 +61,14 @@
|
||||
android:id="@+id/gyro_mouse_enabled"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/gyro_mouse_enabled"
|
||||
android:title="Gyro mouse" />
|
||||
android:title="@string/gyro_mouse_enabled_title" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:id="@+id/mousepad_gyro_sensitivity"
|
||||
android:defaultValue="100"
|
||||
android:key="@string/gyro_mouse_sensitivity"
|
||||
android:title="@string/gyro_mouse_sensitivity_title"
|
||||
android:layout_width="wrap_content" />
|
||||
|
||||
<SwitchPreference
|
||||
android:id="@+id/mousepad_mouse_buttons_enabled_pref"
|
||||
|
@@ -66,7 +66,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
private DatagramSocket udpServer;
|
||||
|
||||
private long lastBroadcast = 0;
|
||||
private final static long delayBetweenBroadcasts = 500;
|
||||
private final static long delayBetweenBroadcasts = 200;
|
||||
|
||||
private boolean listening = false;
|
||||
|
||||
@@ -385,7 +385,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
}
|
||||
|
||||
if (bytes != null) {
|
||||
//Log.e("KDE/LanLinkProvider","Sending packet to "+iplist.size()+" ips");
|
||||
Log.i("KDE/LanLinkProvider","Sending broadcast to "+iplist.size()+" ips");
|
||||
for (String ipstr : iplist) {
|
||||
try {
|
||||
InetAddress client = InetAddress.getByName(ipstr);
|
||||
|
@@ -209,7 +209,7 @@ public class SslHelper {
|
||||
trustManagerFactory.init(keyStore);
|
||||
|
||||
// Setup custom trust manager if device not trusted
|
||||
SSLContext tlsContext = SSLContext.getInstance("TLS");
|
||||
SSLContext tlsContext = SSLContext.getInstance("TLSv1.2"); // Use TLS up to 1.2, since 1.3 seems to cause issues in some (older?) devices
|
||||
if (isDeviceTrusted) {
|
||||
tlsContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), RandomHelper.secureRandom);
|
||||
} else {
|
||||
|
@@ -151,7 +151,7 @@ public class ConnectivityReportPlugin extends Plugin {
|
||||
|
||||
serializeSignalStrengths();
|
||||
device.sendPacket(connectivityInfo);
|
||||
Log.i("ConnectivityReport", "signalStrength of #" + subID + " updated to " + level);
|
||||
//Log.i("ConnectivityReport", "signalStrength of #" + subID + " updated to " + level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,7 +164,7 @@ public class ConnectivityReportPlugin extends Plugin {
|
||||
|
||||
serializeSignalStrengths();
|
||||
device.sendPacket(connectivityInfo);
|
||||
Log.i("ConnectivityReport", "networkType of #" + subID + " updated to " + networkTypeToString(networkType));
|
||||
//Log.i("ConnectivityReport", "networkType of #" + subID + " updated to " + networkTypeToString(networkType));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Forrest Hilton <forrestmhilton@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
|
||||
package org.kde.kdeconnect.Plugins.MousePadPlugin;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
public class ComposeSendActivity extends AppCompatActivity {
|
||||
|
||||
private String deviceId;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_compose_send);
|
||||
|
||||
setSupportActionBar(findViewById(R.id.toolbar));
|
||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
|
||||
Intent intent = getIntent();
|
||||
|
||||
deviceId = intent.getStringExtra("org.kde.kdeconnect.Plugins.MousePadPlugin.deviceId");
|
||||
|
||||
EditText editText = findViewById(R.id.compose);
|
||||
|
||||
editText.requestFocus();
|
||||
// this is almost never used
|
||||
editText.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if (actionId == EditorInfo.IME_ACTION_SEND) {
|
||||
sendComposed();
|
||||
return true;
|
||||
}
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public void sendChars(CharSequence chars) {
|
||||
final NetworkPacket np = new NetworkPacket(MousePadPlugin.PACKET_TYPE_MOUSEPAD_REQUEST);
|
||||
np.set("key", chars.toString());
|
||||
sendKeyPressPacket(np);
|
||||
}
|
||||
|
||||
private void sendKeyPressPacket(final NetworkPacket np) {
|
||||
try {
|
||||
Log.d("packed", np.serialize());
|
||||
} catch (Exception e) {
|
||||
Log.e("KDE/ComposeSend", "Exception", e);
|
||||
}
|
||||
|
||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> plugin.sendKeyboardPacket(np));
|
||||
}
|
||||
|
||||
public void sendComposed() {
|
||||
EditText editText = findViewById(R.id.compose);
|
||||
|
||||
String editTextStr = editText.getText().toString();
|
||||
sendChars(editTextStr);
|
||||
clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
EditText editText = findViewById(R.id.compose);
|
||||
editText.setText("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_compose_send, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.menu_clear_compose) {
|
||||
clear();
|
||||
return true;
|
||||
} else if (id == R.id.menu_send_compose) {
|
||||
sendComposed();
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Dmitry Yudin <dgyudin@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.Plugins.MousePadPlugin
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Send
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.accompanist.themeadapter.material3.Mdc3Theme
|
||||
import org.kde.kdeconnect.BackgroundService
|
||||
import org.kde.kdeconnect.NetworkPacket
|
||||
import org.kde.kdeconnect.UserInterface.compose.KdeTextButton
|
||||
import org.kde.kdeconnect.UserInterface.compose.KdeTextField
|
||||
import org.kde.kdeconnect.UserInterface.compose.KdeTopAppBar
|
||||
import org.kde.kdeconnect_tp.R
|
||||
|
||||
private const val INPUT_CACHE_KEY = "compose_send_input_cache"
|
||||
|
||||
class ComposeSendActivity : AppCompatActivity() {
|
||||
private var deviceId: String? = null
|
||||
private val userInput = mutableStateOf(String())
|
||||
private val prefs by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
prefs.getString(INPUT_CACHE_KEY, null)?.let { userInput.value = it }
|
||||
|
||||
setContent { ComposeSendScreen() }
|
||||
|
||||
deviceId = intent.getStringExtra("org.kde.kdeconnect.Plugins.MousePadPlugin.deviceId")
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
with(prefs.edit()) {
|
||||
if (userInput.value.isNotBlank()) putString(INPUT_CACHE_KEY, userInput.value) else remove(INPUT_CACHE_KEY)
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendChars(chars: String) {
|
||||
val np = NetworkPacket(MousePadPlugin.PACKET_TYPE_MOUSEPAD_REQUEST)
|
||||
np["key"] = chars
|
||||
sendKeyPressPacket(np)
|
||||
}
|
||||
|
||||
private fun sendKeyPressPacket(np: NetworkPacket) {
|
||||
try {
|
||||
Log.d("packed", np.serialize())
|
||||
} catch (e: Exception) {
|
||||
Log.e("KDE/ComposeSend", "Exception", e)
|
||||
}
|
||||
BackgroundService.RunWithPlugin(
|
||||
this, deviceId, MousePadPlugin::class.java
|
||||
) { plugin: MousePadPlugin -> plugin.sendKeyboardPacket(np) }
|
||||
}
|
||||
|
||||
private fun sendComposed() {
|
||||
sendChars(userInput.value)
|
||||
clearComposeInput()
|
||||
}
|
||||
|
||||
private fun clearComposeInput() {
|
||||
userInput.value = String()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ComposeSendScreen() {
|
||||
Mdc3Theme {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
KdeTopAppBar(
|
||||
title = stringResource(R.string.compose_send_title),
|
||||
navIcon = Icons.Default.ArrowBack,
|
||||
navIconOnClick = { onBackPressedDispatcher.onBackPressed() },
|
||||
actions = {
|
||||
KdeTextButton(
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
onClick = { clearComposeInput() },
|
||||
text = stringResource(R.string.clear_compose),
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
) { scaffoldPadding ->
|
||||
Box(modifier = Modifier.padding(scaffoldPadding).fillMaxSize()) {
|
||||
KdeTextField(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 80.dp)
|
||||
.align(Alignment.BottomStart)
|
||||
.fillMaxWidth(),
|
||||
input = userInput,
|
||||
label = stringResource(R.string.click_here_to_type),
|
||||
)
|
||||
KdeTextButton(
|
||||
onClick = { sendComposed() },
|
||||
modifier = Modifier.padding(all = 16.dp).align(Alignment.BottomEnd),
|
||||
enabled = userInput.value.isNotEmpty(),
|
||||
text = stringResource(R.string.send_compose),
|
||||
iconLeft = Icons.Default.Send,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,6 +8,10 @@ package org.kde.kdeconnect.Plugins.MousePadPlugin;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
@@ -15,17 +19,11 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.Sensor;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
|
||||
@@ -33,7 +31,13 @@ import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MousePadActivity extends AppCompatActivity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, MousePadGestureDetector.OnGestureListener, SensorEventListener {
|
||||
public class MousePadActivity
|
||||
extends AppCompatActivity
|
||||
implements GestureDetector.OnGestureListener,
|
||||
GestureDetector.OnDoubleTapListener,
|
||||
MousePadGestureDetector.OnGestureListener,
|
||||
SensorEventListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private String deviceId;
|
||||
|
||||
private final static float MinDistanceToSendScroll = 2.5f; // touch gesture scroll
|
||||
@@ -49,6 +53,7 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
private int scrollDirection = 1;
|
||||
private boolean allowGyro = false;
|
||||
private boolean gyroEnabled = false;
|
||||
private int gyroscopeSensitivity = 100;
|
||||
private boolean isScrolling = false;
|
||||
private float accumulatedDistanceY = 0;
|
||||
|
||||
@@ -63,6 +68,8 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
|
||||
private SharedPreferences prefs = null;
|
||||
|
||||
private boolean prefsApplied = false;
|
||||
|
||||
enum ClickType {
|
||||
LEFT, RIGHT, MIDDLE, NONE;
|
||||
|
||||
@@ -90,27 +97,25 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
float[] values = event.values;
|
||||
|
||||
float X = -values[2] * 70 * mCurrentSensitivity * displayDpiMultiplier;
|
||||
float Y = -values[0] * 70 * mCurrentSensitivity * displayDpiMultiplier;
|
||||
float X = -values[2] * 70 * (gyroscopeSensitivity/100.0f);
|
||||
float Y = -values[0] * 70 * (gyroscopeSensitivity/100.0f);
|
||||
|
||||
if (X < 0.25 && X > -0.25) {
|
||||
X = 0;
|
||||
} else {
|
||||
X = X * mCurrentSensitivity * displayDpiMultiplier;
|
||||
X = X * (gyroscopeSensitivity/100.0f);
|
||||
}
|
||||
|
||||
if (Y < 0.25 && Y > -0.25) {
|
||||
Y = 0;
|
||||
} else {
|
||||
Y = Y * mCurrentSensitivity * displayDpiMultiplier;
|
||||
Y = Y * (gyroscopeSensitivity/100.0f);
|
||||
}
|
||||
|
||||
final float nX = X;
|
||||
final float nY = Y;
|
||||
|
||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> {
|
||||
plugin.sendMouseDelta(nX, nY);
|
||||
});
|
||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> plugin.sendMouseDelta(nX, nY));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,6 +128,10 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
|
||||
findViewById(R.id.mouse_click_left).setOnClickListener(v -> sendLeftClick());
|
||||
findViewById(R.id.mouse_click_middle).setOnClickListener(v -> sendMiddleClick());
|
||||
findViewById(R.id.mouse_click_right).setOnClickListener(v -> sendRightClick());
|
||||
|
||||
deviceId = getIntent().getStringExtra("deviceId");
|
||||
|
||||
getWindow().getDecorView().setHapticFeedbackEnabled(true);
|
||||
@@ -136,57 +145,13 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
keyListenerView.setDeviceId(deviceId);
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
if (prefs.getBoolean(getString(R.string.mousepad_scroll_direction), false)) {
|
||||
scrollDirection = -1;
|
||||
} else {
|
||||
scrollDirection = 1;
|
||||
}
|
||||
if (mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null
|
||||
&& prefs.getBoolean(getString(R.string.gyro_mouse_enabled), false)) {
|
||||
allowGyro = true;
|
||||
}
|
||||
String singleTapSetting = prefs.getString(getString(R.string.mousepad_single_tap_key),
|
||||
getString(R.string.mousepad_default_single));
|
||||
String doubleTapSetting = prefs.getString(getString(R.string.mousepad_double_tap_key),
|
||||
getString(R.string.mousepad_default_double));
|
||||
String tripleTapSetting = prefs.getString(getString(R.string.mousepad_triple_tap_key),
|
||||
getString(R.string.mousepad_default_triple));
|
||||
String sensitivitySetting = prefs.getString(getString(R.string.mousepad_sensitivity_key),
|
||||
getString(R.string.mousepad_default_sensitivity));
|
||||
|
||||
String accelerationProfileName = prefs.getString(getString(R.string.mousepad_acceleration_profile_key),
|
||||
getString(R.string.mousepad_default_acceleration_profile));
|
||||
|
||||
mPointerAccelerationProfile = PointerAccelerationProfileFactory.getProfileWithName(accelerationProfileName);
|
||||
|
||||
singleTapAction = ClickType.fromString(singleTapSetting);
|
||||
doubleTapAction = ClickType.fromString(doubleTapSetting);
|
||||
tripleTapAction = ClickType.fromString(tripleTapSetting);
|
||||
applyPrefs();
|
||||
|
||||
//Technically xdpi and ydpi should be handled separately,
|
||||
//but since ydpi is usually almost equal to xdpi, only xdpi is used for the multiplier.
|
||||
displayDpiMultiplier = StandardDpi / getResources().getDisplayMetrics().xdpi;
|
||||
switch (sensitivitySetting) {
|
||||
case "slowest":
|
||||
mCurrentSensitivity = 0.2f;
|
||||
break;
|
||||
case "aboveSlowest":
|
||||
mCurrentSensitivity = 0.5f;
|
||||
break;
|
||||
case "default":
|
||||
mCurrentSensitivity = 1.0f;
|
||||
break;
|
||||
case "aboveDefault":
|
||||
mCurrentSensitivity = 1.5f;
|
||||
break;
|
||||
case "fastest":
|
||||
mCurrentSensitivity = 2.0f;
|
||||
break;
|
||||
default:
|
||||
mCurrentSensitivity = 1.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
final View decorView = getWindow().getDecorView();
|
||||
decorView.setOnSystemUiVisibilityChangeListener(visibility -> {
|
||||
@@ -205,19 +170,13 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
applyPrefs();
|
||||
|
||||
if (allowGyro && !gyroEnabled) {
|
||||
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME);
|
||||
gyroEnabled = true;
|
||||
}
|
||||
|
||||
if (prefs.getBoolean(getString(R.string.mousepad_mouse_buttons_enabled_pref), true)) {
|
||||
findViewById(R.id.mouse_buttons).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.mouse_click_left).setOnClickListener(v -> sendLeftClick());
|
||||
findViewById(R.id.mouse_click_middle).setOnClickListener(v -> sendMiddleClick());
|
||||
findViewById(R.id.mouse_click_right).setOnClickListener(v -> sendRightClick());
|
||||
} else {
|
||||
findViewById(R.id.mouse_buttons).setVisibility(View.GONE);
|
||||
}
|
||||
invalidateMenu();
|
||||
|
||||
super.onResume();
|
||||
@@ -232,7 +191,8 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override protected void onStop() {
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (gyroEnabled) {
|
||||
mSensorManager.unregisterListener(this);
|
||||
gyroEnabled = false;
|
||||
@@ -240,6 +200,12 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
@@ -465,6 +431,11 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (prefsApplied) prefsApplied = false;
|
||||
}
|
||||
|
||||
|
||||
private void sendLeftClick() {
|
||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, MousePadPlugin::sendLeftClick);
|
||||
@@ -482,7 +453,6 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> plugin.sendScroll(0, y));
|
||||
}
|
||||
|
||||
//TODO: Does not work on KitKat with or without requestFocus()
|
||||
private void showKeyboard() {
|
||||
InputMethodManager imm = ContextCompat.getSystemService(this, InputMethodManager.class);
|
||||
keyListenerView.requestFocus();
|
||||
@@ -495,6 +465,70 @@ public class MousePadActivity extends AppCompatActivity implements GestureDetect
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void applyPrefs() {
|
||||
if (prefsApplied) return;
|
||||
|
||||
if (prefs.getBoolean(getString(R.string.mousepad_scroll_direction), false)) {
|
||||
scrollDirection = -1;
|
||||
} else {
|
||||
scrollDirection = 1;
|
||||
}
|
||||
|
||||
allowGyro = isGyroSensorAvailable() && prefs.getBoolean(getString(R.string.gyro_mouse_enabled), false);
|
||||
if (allowGyro) gyroscopeSensitivity = prefs.getInt(getString(R.string.gyro_mouse_sensitivity), 100);
|
||||
|
||||
String singleTapSetting = prefs.getString(getString(R.string.mousepad_single_tap_key),
|
||||
getString(R.string.mousepad_default_single));
|
||||
String doubleTapSetting = prefs.getString(getString(R.string.mousepad_double_tap_key),
|
||||
getString(R.string.mousepad_default_double));
|
||||
String tripleTapSetting = prefs.getString(getString(R.string.mousepad_triple_tap_key),
|
||||
getString(R.string.mousepad_default_triple));
|
||||
String sensitivitySetting = prefs.getString(getString(R.string.mousepad_sensitivity_key),
|
||||
getString(R.string.mousepad_default_sensitivity));
|
||||
|
||||
String accelerationProfileName = prefs.getString(getString(R.string.mousepad_acceleration_profile_key),
|
||||
getString(R.string.mousepad_default_acceleration_profile));
|
||||
|
||||
mPointerAccelerationProfile = PointerAccelerationProfileFactory.getProfileWithName(accelerationProfileName);
|
||||
|
||||
singleTapAction = ClickType.fromString(singleTapSetting);
|
||||
doubleTapAction = ClickType.fromString(doubleTapSetting);
|
||||
tripleTapAction = ClickType.fromString(tripleTapSetting);
|
||||
|
||||
switch (sensitivitySetting) {
|
||||
case "slowest":
|
||||
mCurrentSensitivity = 0.2f;
|
||||
break;
|
||||
case "aboveSlowest":
|
||||
mCurrentSensitivity = 0.5f;
|
||||
break;
|
||||
case "default":
|
||||
mCurrentSensitivity = 1.0f;
|
||||
break;
|
||||
case "aboveDefault":
|
||||
mCurrentSensitivity = 1.5f;
|
||||
break;
|
||||
case "fastest":
|
||||
mCurrentSensitivity = 2.0f;
|
||||
break;
|
||||
default:
|
||||
mCurrentSensitivity = 1.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefs.getBoolean(getString(R.string.mousepad_mouse_buttons_enabled_pref), true)) {
|
||||
findViewById(R.id.mouse_buttons).setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
findViewById(R.id.mouse_buttons).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
prefsApplied = true;
|
||||
}
|
||||
|
||||
private boolean isGyroSensorAvailable() {
|
||||
return mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
super.onBackPressed();
|
||||
|
@@ -21,7 +21,7 @@ import org.kde.kdeconnect.UserInterface.MainActivity;
|
||||
import org.kde.kdeconnect.UserInterface.StartActivityAlertDialogFragment;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
@PluginFactory.LoadablePlugin
|
||||
//@PluginFactory.LoadablePlugin
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public class MouseReceiverPlugin extends Plugin {
|
||||
private final static String PACKET_TYPE_MOUSEPAD_REQUEST = "kdeconnect.mousepad.request";
|
||||
|
@@ -6,7 +6,6 @@
|
||||
package org.kde.kdeconnect.Plugins.MprisPlugin
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager.NameNotFoundException
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.ConnectivityManager
|
||||
@@ -20,6 +19,7 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.kde.kdeconnect.NetworkPacket.Payload
|
||||
import org.kde.kdeconnect_tp.BuildConfig
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
@@ -78,14 +78,9 @@ internal object AlbumArtCache {
|
||||
fun initializeDiskCache(context: Context) {
|
||||
if (this::diskCache.isInitialized) return
|
||||
val cacheDir = File(context.cacheDir, "album_art")
|
||||
val versionCode: Int
|
||||
try {
|
||||
val info = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
versionCode = info.versionCode
|
||||
//Initialize the disk cache with a limit of 5 MB storage (fits ~830 images, taking Spotify as reference)
|
||||
diskCache = DiskLruCache.open(cacheDir, versionCode, 1, 1000 * 1000 * 5.toLong())
|
||||
} catch (e: NameNotFoundException) {
|
||||
throw AssertionError(e)
|
||||
diskCache = DiskLruCache.open(cacheDir, BuildConfig.VERSION_CODE, 1, 1000 * 1000 * 5.toLong())
|
||||
} catch (e: IOException) {
|
||||
Log.e("KDE/Mpris/AlbumArtCache", "Could not open the album art disk cache!", e)
|
||||
}
|
||||
|
@@ -67,8 +67,10 @@ public class SystemVolumePlugin extends Plugin {
|
||||
Log.e("KDEConnect", "Exception", e);
|
||||
}
|
||||
|
||||
for (SinkListener l : listeners) {
|
||||
l.sinksChanged();
|
||||
synchronized(listeners) {
|
||||
for (SinkListener l : listeners) {
|
||||
l.sinksChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -140,11 +142,15 @@ public class SystemVolumePlugin extends Plugin {
|
||||
}
|
||||
|
||||
void addSinkListener(SinkListener listener) {
|
||||
listeners.add(listener);
|
||||
synchronized(listeners) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void removeSinkListener(SinkListener listener) {
|
||||
listeners.remove(listener);
|
||||
synchronized(listeners) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -221,18 +221,20 @@ class DeviceFragment : Fragment() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
requireView().isFocusableInTouchMode = true
|
||||
requireView().requestFocus()
|
||||
requireView().setOnKeyListener { view, keyCode, event ->
|
||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
val fromDeviceList = requireArguments().getBoolean(ARG_FROM_DEVICE_LIST, false)
|
||||
// Handle back button, so we go to the list of devices in case we came from there
|
||||
if (fromDeviceList) {
|
||||
mActivity?.onDeviceSelected(null)
|
||||
return@setOnKeyListener true
|
||||
with(requireView()) {
|
||||
isFocusableInTouchMode = true
|
||||
requestFocus()
|
||||
setOnKeyListener { _, keyCode, event ->
|
||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
val fromDeviceList = requireArguments().getBoolean(ARG_FROM_DEVICE_LIST, false)
|
||||
// Handle back button, so we go to the list of devices in case we came from there
|
||||
if (fromDeviceList) {
|
||||
mActivity?.onDeviceSelected(null)
|
||||
return@setOnKeyListener true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,4 +418,8 @@ class DeviceFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
mActivity?.supportActionBar?.subtitle = null
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ class PluginItem(
|
||||
textStyleRes: Int? = null,
|
||||
) : this(
|
||||
context = context,
|
||||
header = plugin.displayName,
|
||||
header = plugin.actionName,
|
||||
textStyleRes = textStyleRes,
|
||||
) {
|
||||
this.action = { action(plugin) }
|
||||
|
@@ -1,429 +0,0 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
import org.kde.kdeconnect.Plugins.SharePlugin.ShareSettingsFragment;
|
||||
import org.kde.kdeconnect.UserInterface.About.AboutFragment;
|
||||
import org.kde.kdeconnect.UserInterface.About.ApplicationAboutDataKt;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
import org.kde.kdeconnect_tp.databinding.ActivityMainBinding;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final int MENU_ENTRY_ADD_DEVICE = 1; //0 means no-selection
|
||||
private static final int MENU_ENTRY_SETTINGS = 2;
|
||||
private static final int MENU_ENTRY_ABOUT = 3;
|
||||
private static final int MENU_ENTRY_DEVICE_FIRST_ID = 1000; //All subsequent ids are devices in the menu
|
||||
private static final int MENU_ENTRY_DEVICE_UNKNOWN = 9999; //It's still a device, but we don't know which one yet
|
||||
private static final int STORAGE_LOCATION_CONFIGURED = 2020;
|
||||
|
||||
private static final String STATE_SELECTED_MENU_ENTRY = "selected_entry"; //Saved only in onSaveInstanceState
|
||||
private static final String STATE_SELECTED_DEVICE = "selected_device"; //Saved persistently in preferences
|
||||
|
||||
public static final int RESULT_NEEDS_RELOAD = Activity.RESULT_FIRST_USER;
|
||||
|
||||
public static final String PAIR_REQUEST_STATUS = "pair_req_status";
|
||||
public static final String PAIRING_ACCEPTED = "accepted";
|
||||
public static final String PAIRING_REJECTED = "rejected";
|
||||
public static final String PAIRING_PENDING = "pending";
|
||||
|
||||
public static final String EXTRA_DEVICE_ID = "deviceId";
|
||||
public static final String FLAG_FORCE_OVERVIEW = "forceOverview";
|
||||
|
||||
private NavigationView mNavigationView;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private TextView mNavViewDeviceName;
|
||||
|
||||
private String mCurrentDevice;
|
||||
private int mCurrentMenuEntry;
|
||||
|
||||
private SharedPreferences preferences;
|
||||
|
||||
private final HashMap<MenuItem, String> mMapMenuToDeviceId = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
DeviceHelper.initializeDeviceId(this);
|
||||
|
||||
final ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
mNavigationView = binding.navigationDrawer;
|
||||
mDrawerLayout = binding.drawerLayout;
|
||||
|
||||
View mDrawerHeader = mNavigationView.getHeaderView(0);
|
||||
mNavViewDeviceName = mDrawerHeader.findViewById(R.id.device_name);
|
||||
ImageView mNavViewDeviceType = mDrawerHeader.findViewById(R.id.device_type);
|
||||
|
||||
setSupportActionBar(binding.toolbarLayout.toolbar);
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
if (mDrawerLayout != null) {
|
||||
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
|
||||
mDrawerLayout, /* DrawerLayout object */
|
||||
R.string.open, /* "open drawer" description */
|
||||
R.string.close /* "close drawer" description */
|
||||
);
|
||||
|
||||
mDrawerLayout.addDrawerListener(mDrawerToggle);
|
||||
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
|
||||
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
mDrawerToggle.setDrawerIndicatorEnabled(true);
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
|
||||
preferences = getSharedPreferences("stored_menu_selection", Context.MODE_PRIVATE);
|
||||
|
||||
// Note: The preference changed listener should be registered before getting the name, because getting
|
||||
// it can trigger a background fetch from the internet that will eventually update the preference
|
||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
|
||||
String deviceName = DeviceHelper.getDeviceName(this);
|
||||
mNavViewDeviceType.setImageDrawable(DeviceHelper.getDeviceType(this).getIcon(this));
|
||||
mNavViewDeviceName.setText(deviceName);
|
||||
|
||||
mNavigationView.setNavigationItemSelectedListener(menuItem -> {
|
||||
mCurrentMenuEntry = menuItem.getItemId();
|
||||
switch (mCurrentMenuEntry) {
|
||||
case MENU_ENTRY_ADD_DEVICE:
|
||||
mCurrentDevice = null;
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply();
|
||||
setContentFragment(new PairingFragment());
|
||||
break;
|
||||
case MENU_ENTRY_SETTINGS:
|
||||
mCurrentDevice = null;
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply();
|
||||
setContentFragment(new SettingsFragment());
|
||||
break;
|
||||
case MENU_ENTRY_ABOUT:
|
||||
mCurrentDevice = null;
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply();
|
||||
setContentFragment(AboutFragment.newInstance(Objects.requireNonNull(ApplicationAboutDataKt.getApplicationAboutData(this))));
|
||||
break;
|
||||
default:
|
||||
String deviceId = mMapMenuToDeviceId.get(menuItem);
|
||||
onDeviceSelected(deviceId);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mDrawerLayout != null) {
|
||||
mDrawerLayout.closeDrawer(mNavigationView);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Decide which menu entry should be selected at start
|
||||
String savedDevice;
|
||||
int savedMenuEntry;
|
||||
if (getIntent().hasExtra(FLAG_FORCE_OVERVIEW)) {
|
||||
Log.i("MainActivity", "Requested to start main overview");
|
||||
savedDevice = null;
|
||||
savedMenuEntry = MENU_ENTRY_ADD_DEVICE;
|
||||
} else if (getIntent().hasExtra(EXTRA_DEVICE_ID)) {
|
||||
Log.i("MainActivity", "Loading selected device from parameter");
|
||||
savedDevice = getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
||||
savedMenuEntry = MENU_ENTRY_DEVICE_UNKNOWN;
|
||||
// If pairStatus is not empty, then the user has accepted/reject the pairing from the notification
|
||||
String pairStatus = getIntent().getStringExtra(PAIR_REQUEST_STATUS);
|
||||
if (pairStatus != null) {
|
||||
Log.i("MainActivity", "pair status is " + pairStatus);
|
||||
savedDevice = onPairResultFromNotification(savedDevice, pairStatus);
|
||||
if (savedDevice == null) {
|
||||
savedMenuEntry = MENU_ENTRY_ADD_DEVICE;
|
||||
}
|
||||
}
|
||||
} else if (savedInstanceState != null) {
|
||||
Log.i("MainActivity", "Loading selected device from saved activity state");
|
||||
savedDevice = savedInstanceState.getString(STATE_SELECTED_DEVICE);
|
||||
savedMenuEntry = savedInstanceState.getInt(STATE_SELECTED_MENU_ENTRY, MENU_ENTRY_ADD_DEVICE);
|
||||
} else {
|
||||
Log.i("MainActivity", "Loading selected device from persistent storage");
|
||||
savedDevice = preferences.getString(STATE_SELECTED_DEVICE, null);
|
||||
savedMenuEntry = (savedDevice != null)? MENU_ENTRY_DEVICE_UNKNOWN : MENU_ENTRY_ADD_DEVICE;
|
||||
}
|
||||
|
||||
mCurrentMenuEntry = savedMenuEntry;
|
||||
mCurrentDevice = savedDevice;
|
||||
mNavigationView.setCheckedItem(savedMenuEntry);
|
||||
|
||||
//FragmentManager will restore whatever fragment was there
|
||||
if (savedInstanceState != null) {
|
||||
Fragment frag = getSupportFragmentManager().findFragmentById(R.id.container);
|
||||
if (!(frag instanceof DeviceFragment) || ((DeviceFragment)frag).getDeviceId().equals(savedDevice)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Activate the chosen fragment and select the entry in the menu
|
||||
if (savedMenuEntry >= MENU_ENTRY_DEVICE_FIRST_ID && savedDevice != null) {
|
||||
onDeviceSelected(savedDevice);
|
||||
} else {
|
||||
if (mCurrentMenuEntry == MENU_ENTRY_SETTINGS) {
|
||||
setContentFragment(new SettingsFragment());
|
||||
} else if (mCurrentMenuEntry == MENU_ENTRY_ABOUT) {
|
||||
setContentFragment(AboutFragment.newInstance(Objects.requireNonNull(ApplicationAboutDataKt.getApplicationAboutData(this))));
|
||||
} else {
|
||||
setContentFragment(new PairingFragment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
private String onPairResultFromNotification(String deviceId, String pairStatus) {
|
||||
assert(deviceId != null);
|
||||
|
||||
if (!pairStatus.equals(PAIRING_PENDING)) {
|
||||
BackgroundService.RunCommand(this, service -> {
|
||||
Device device = service.getDevice(deviceId);
|
||||
if (device == null) {
|
||||
Log.w("rejectPairing", "Device no longer exists: " + deviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pairStatus.equals(PAIRING_ACCEPTED)) {
|
||||
device.acceptPairing();
|
||||
} else if (pairStatus.equals(PAIRING_REJECTED)) {
|
||||
device.rejectPairing();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pairStatus.equals(PAIRING_ACCEPTED) || pairStatus.equals(PAIRING_PENDING)) {
|
||||
return deviceId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private int deviceIdToMenuEntryId(String deviceId) {
|
||||
for (HashMap.Entry<MenuItem, String> entry : mMapMenuToDeviceId.entrySet()) {
|
||||
if (TextUtils.equals(entry.getValue(), deviceId)) { //null-safe
|
||||
return entry.getKey().getItemId();
|
||||
}
|
||||
}
|
||||
return MENU_ENTRY_DEVICE_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mNavigationView)) {
|
||||
mDrawerLayout.closeDrawer(mNavigationView);
|
||||
} else if (mCurrentMenuEntry == MENU_ENTRY_SETTINGS || mCurrentMenuEntry == MENU_ENTRY_ABOUT) {
|
||||
mCurrentMenuEntry = MENU_ENTRY_ADD_DEVICE;
|
||||
mNavigationView.setCheckedItem(MENU_ENTRY_ADD_DEVICE);
|
||||
setContentFragment(new PairingFragment());
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (mDrawerLayout != null && item.getItemId() == android.R.id.home) {
|
||||
mDrawerLayout.openDrawer(mNavigationView);
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDeviceList() {
|
||||
BackgroundService.RunCommand(MainActivity.this, service -> {
|
||||
|
||||
Menu menu = mNavigationView.getMenu();
|
||||
menu.clear();
|
||||
mMapMenuToDeviceId.clear();
|
||||
|
||||
SubMenu devicesMenu = menu.addSubMenu(R.string.devices);
|
||||
|
||||
int id = MENU_ENTRY_DEVICE_FIRST_ID;
|
||||
Collection<Device> devices = service.getDevices().values();
|
||||
for (Device device : devices) {
|
||||
if (device.isReachable() && device.isPaired()) {
|
||||
MenuItem item = devicesMenu.add(Menu.FIRST, id++, 1, device.getName());
|
||||
item.setIcon(device.getIcon());
|
||||
item.setCheckable(true);
|
||||
mMapMenuToDeviceId.put(item, device.getDeviceId());
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem addDeviceItem = devicesMenu.add(Menu.FIRST, MENU_ENTRY_ADD_DEVICE, 1000, R.string.pair_new_device);
|
||||
addDeviceItem.setIcon(R.drawable.ic_action_content_add_circle_outline_32dp);
|
||||
addDeviceItem.setCheckable(true);
|
||||
|
||||
MenuItem settingsItem = menu.add(Menu.FIRST, MENU_ENTRY_SETTINGS, 1000, R.string.settings);
|
||||
settingsItem.setIcon(R.drawable.ic_settings_white_32dp);
|
||||
settingsItem.setCheckable(true);
|
||||
|
||||
MenuItem aboutItem = menu.add(Menu.FIRST, MENU_ENTRY_ABOUT, 1000, R.string.about);
|
||||
aboutItem.setIcon(R.drawable.ic_baseline_info_24);
|
||||
aboutItem.setCheckable(true);
|
||||
|
||||
//Ids might have changed
|
||||
if (mCurrentMenuEntry >= MENU_ENTRY_DEVICE_FIRST_ID) {
|
||||
mCurrentMenuEntry = deviceIdToMenuEntryId(mCurrentDevice);
|
||||
}
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
BackgroundService.RunCommand(this, service -> {
|
||||
service.onNetworkChange();
|
||||
service.addDeviceListChangedCallback("MainActivity", unused -> updateDeviceList());
|
||||
});
|
||||
updateDeviceList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
BackgroundService.RunCommand(this, service -> service.removeDeviceListChangedCallback("MainActivity"));
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private static void uncheckAllMenuItems(Menu menu) {
|
||||
int size = menu.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
MenuItem item = menu.getItem(i);
|
||||
if(item.hasSubMenu()) {
|
||||
uncheckAllMenuItems(item.getSubMenu());
|
||||
} else {
|
||||
item.setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeviceSelected(String deviceId, boolean fromDeviceList) {
|
||||
mCurrentDevice = deviceId;
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, deviceId).apply();
|
||||
|
||||
if (mCurrentDevice != null) {
|
||||
mCurrentMenuEntry = deviceIdToMenuEntryId(deviceId);
|
||||
if (mCurrentMenuEntry == MENU_ENTRY_DEVICE_UNKNOWN) {
|
||||
uncheckAllMenuItems(mNavigationView.getMenu());
|
||||
} else {
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry);
|
||||
}
|
||||
setContentFragment(DeviceFragment.Companion.newInstance(deviceId, fromDeviceList));
|
||||
} else {
|
||||
mCurrentMenuEntry = MENU_ENTRY_ADD_DEVICE;
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry);
|
||||
setContentFragment(new PairingFragment());
|
||||
}
|
||||
}
|
||||
|
||||
private void setContentFragment(Fragment fragment) {
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.container, fragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void onDeviceSelected(String deviceId) {
|
||||
onDeviceSelected(deviceId, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(STATE_SELECTED_DEVICE, mCurrentDevice);
|
||||
outState.putInt(STATE_SELECTED_MENU_ENTRY, mCurrentMenuEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == RESULT_NEEDS_RELOAD) {
|
||||
BackgroundService.RunCommand(this, service -> {
|
||||
Device device = service.getDevice(mCurrentDevice);
|
||||
device.reloadPluginsFromSettings();
|
||||
});
|
||||
} else if (requestCode == STORAGE_LOCATION_CONFIGURED && resultCode == RESULT_OK && data != null){
|
||||
Uri uri = data.getData();
|
||||
ShareSettingsFragment.saveStorageLocationPreference(this, uri);
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode,permissions,grantResults);
|
||||
boolean permissionsGranted = ArrayUtils.contains(grantResults, PackageManager.PERMISSION_GRANTED);
|
||||
if (permissionsGranted) {
|
||||
int i = ArrayUtils.indexOf(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
boolean writeStoragePermissionGranted = (i != ArrayUtils.INDEX_NOT_FOUND &&
|
||||
grantResults[i] == PackageManager.PERMISSION_GRANTED);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && writeStoragePermissionGranted) {
|
||||
// To get a writeable path manually on Android 10 and later for Share and Receive Plugin.
|
||||
// Otherwise Receiving files will keep failing until the user chooses a path manually to receive files.
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
startActivityForResult(intent, STORAGE_LOCATION_CONFIGURED);
|
||||
}
|
||||
|
||||
//New permission granted, reload plugins
|
||||
BackgroundService.RunCommand(this, service -> {
|
||||
Device device = service.getDevice(mCurrentDevice);
|
||||
device.reloadPluginsFromSettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (DeviceHelper.KEY_DEVICE_NAME_PREFERENCE.equals(key)) {
|
||||
mNavViewDeviceName.setText(DeviceHelper.getDeviceName(this));
|
||||
BackgroundService.RunCommand(this, BackgroundService::onNetworkChange); //Re-send our identity packet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
396
src/org/kde/kdeconnect/UserInterface/MainActivity.kt
Normal file
396
src/org/kde/kdeconnect/UserInterface/MainActivity.kt
Normal file
@@ -0,0 +1,396 @@
|
||||
package org.kde.kdeconnect.UserInterface
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import org.apache.commons.lang3.ArrayUtils
|
||||
import org.kde.kdeconnect.BackgroundService
|
||||
import org.kde.kdeconnect.Device
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper
|
||||
import org.kde.kdeconnect.Plugins.SharePlugin.ShareSettingsFragment
|
||||
import org.kde.kdeconnect.UserInterface.About.AboutFragment.Companion.newInstance
|
||||
import org.kde.kdeconnect.UserInterface.About.getApplicationAboutData
|
||||
import org.kde.kdeconnect.UserInterface.DeviceFragment.Companion.newInstance
|
||||
import org.kde.kdeconnect_tp.R
|
||||
import org.kde.kdeconnect_tp.databinding.ActivityMainBinding
|
||||
|
||||
private const val MENU_ENTRY_ADD_DEVICE = 1 //0 means no-selection
|
||||
private const val MENU_ENTRY_SETTINGS = 2
|
||||
private const val MENU_ENTRY_ABOUT = 3
|
||||
private const val MENU_ENTRY_DEVICE_FIRST_ID = 1000 //All subsequent ids are devices in the menu
|
||||
private const val MENU_ENTRY_DEVICE_UNKNOWN = 9999 //It's still a device, but we don't know which one yet
|
||||
private const val STORAGE_LOCATION_CONFIGURED = 2020
|
||||
private const val STATE_SELECTED_MENU_ENTRY = "selected_entry" //Saved only in onSaveInstanceState
|
||||
private const val STATE_SELECTED_DEVICE = "selected_device" //Saved persistently in preferences
|
||||
|
||||
class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
||||
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
|
||||
private val mNavigationView: NavigationView by lazy { binding.navigationDrawer }
|
||||
private val mDrawerLayout: DrawerLayout? by lazy { binding.drawerLayout }
|
||||
|
||||
private lateinit var mNavViewDeviceName: TextView
|
||||
|
||||
private var mCurrentDevice: String? = null
|
||||
private var mCurrentMenuEntry = 0
|
||||
private set(value) {
|
||||
field = value
|
||||
//Enabling "go to default fragment on back" callback when user in settings or "about" fragment
|
||||
mainFragmentCallback.isEnabled = value == MENU_ENTRY_SETTINGS || value == MENU_ENTRY_ABOUT
|
||||
}
|
||||
private val preferences: SharedPreferences by lazy { getSharedPreferences("stored_menu_selection", MODE_PRIVATE) }
|
||||
private val mMapMenuToDeviceId = HashMap<MenuItem, String>()
|
||||
|
||||
private val closeDrawerCallback = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() {
|
||||
mDrawerLayout?.closeDrawer(mNavigationView)
|
||||
}
|
||||
}
|
||||
|
||||
private val mainFragmentCallback = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() {
|
||||
mCurrentMenuEntry = mCurrentDevice?.let { deviceIdToMenuEntryId(it) } ?: MENU_ENTRY_ADD_DEVICE
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry)
|
||||
setContentFragment(mCurrentDevice?.let { newInstance(it, false) } ?: PairingFragment())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
DeviceHelper.initializeDeviceId(this)
|
||||
|
||||
setContentView(binding.root)
|
||||
|
||||
val mDrawerHeader = mNavigationView.getHeaderView(0)
|
||||
mNavViewDeviceName = mDrawerHeader.findViewById(R.id.device_name)
|
||||
val mNavViewDeviceType = mDrawerHeader.findViewById<ImageView>(R.id.device_type)
|
||||
|
||||
setSupportActionBar(binding.toolbarLayout.toolbar)
|
||||
mDrawerLayout?.let {
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
val mDrawerToggle = DrawerToggle(it).apply { syncState() }
|
||||
it.addDrawerListener(mDrawerToggle)
|
||||
it.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START)
|
||||
} ?: {
|
||||
supportActionBar?.setDisplayShowHomeEnabled(false)
|
||||
supportActionBar?.setHomeButtonEnabled(false)
|
||||
}
|
||||
|
||||
// Note: The preference changed listener should be registered before getting the name, because getting
|
||||
// it can trigger a background fetch from the internet that will eventually update the preference
|
||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
||||
val deviceName = DeviceHelper.getDeviceName(this)
|
||||
mNavViewDeviceType?.setImageDrawable(DeviceHelper.getDeviceType(this).getIcon(this))
|
||||
mNavViewDeviceName.text = deviceName
|
||||
mNavigationView.setNavigationItemSelectedListener { menuItem: MenuItem ->
|
||||
mCurrentMenuEntry = menuItem.itemId
|
||||
when (mCurrentMenuEntry) {
|
||||
MENU_ENTRY_ADD_DEVICE -> {
|
||||
mCurrentDevice = null
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply()
|
||||
setContentFragment(PairingFragment())
|
||||
}
|
||||
|
||||
MENU_ENTRY_SETTINGS -> {
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply()
|
||||
setContentFragment(SettingsFragment())
|
||||
}
|
||||
|
||||
MENU_ENTRY_ABOUT -> {
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply()
|
||||
setContentFragment(newInstance(getApplicationAboutData(this)))
|
||||
}
|
||||
|
||||
else -> {
|
||||
val deviceId = mMapMenuToDeviceId[menuItem]
|
||||
onDeviceSelected(deviceId)
|
||||
}
|
||||
}
|
||||
mDrawerLayout?.closeDrawer(mNavigationView)
|
||||
true
|
||||
}
|
||||
|
||||
// Decide which menu entry should be selected at start
|
||||
var savedDevice: String?
|
||||
var savedMenuEntry: Int
|
||||
when {
|
||||
intent.hasExtra(FLAG_FORCE_OVERVIEW) -> {
|
||||
Log.i(this::class.simpleName, "Requested to start main overview")
|
||||
savedDevice = null
|
||||
savedMenuEntry = MENU_ENTRY_ADD_DEVICE
|
||||
}
|
||||
|
||||
intent.hasExtra(EXTRA_DEVICE_ID) -> {
|
||||
Log.i(this::class.simpleName, "Loading selected device from parameter")
|
||||
savedDevice = intent.getStringExtra(EXTRA_DEVICE_ID)
|
||||
savedMenuEntry = MENU_ENTRY_DEVICE_UNKNOWN
|
||||
// If pairStatus is not empty, then the user has accepted/reject the pairing from the notification
|
||||
val pairStatus = intent.getStringExtra(PAIR_REQUEST_STATUS)
|
||||
if (pairStatus != null) {
|
||||
Log.i(this::class.simpleName, "Pair status is $pairStatus")
|
||||
savedDevice = onPairResultFromNotification(savedDevice, pairStatus)
|
||||
if (savedDevice == null) {
|
||||
savedMenuEntry = MENU_ENTRY_ADD_DEVICE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
savedInstanceState != null -> {
|
||||
Log.i(this::class.simpleName, "Loading selected device from saved activity state")
|
||||
savedDevice = savedInstanceState.getString(STATE_SELECTED_DEVICE)
|
||||
savedMenuEntry = savedInstanceState.getInt(STATE_SELECTED_MENU_ENTRY, MENU_ENTRY_ADD_DEVICE)
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.i(this::class.simpleName, "Loading selected device from persistent storage")
|
||||
savedDevice = preferences.getString(STATE_SELECTED_DEVICE, null)
|
||||
savedMenuEntry = if (savedDevice != null) MENU_ENTRY_DEVICE_UNKNOWN else MENU_ENTRY_ADD_DEVICE
|
||||
}
|
||||
}
|
||||
mCurrentMenuEntry = savedMenuEntry
|
||||
mCurrentDevice = savedDevice
|
||||
mNavigationView.setCheckedItem(savedMenuEntry)
|
||||
|
||||
//FragmentManager will restore whatever fragment was there
|
||||
if (savedInstanceState != null) {
|
||||
val frag = supportFragmentManager.findFragmentById(R.id.container)
|
||||
if (frag !is DeviceFragment || frag.deviceId == savedDevice) return
|
||||
}
|
||||
|
||||
// Activate the chosen fragment and select the entry in the menu
|
||||
if (savedMenuEntry >= MENU_ENTRY_DEVICE_FIRST_ID && savedDevice != null) {
|
||||
onDeviceSelected(savedDevice)
|
||||
} else {
|
||||
when (mCurrentMenuEntry) {
|
||||
MENU_ENTRY_SETTINGS -> setContentFragment(SettingsFragment())
|
||||
MENU_ENTRY_ABOUT -> setContentFragment(newInstance(getApplicationAboutData(this)))
|
||||
else -> setContentFragment(PairingFragment())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
private fun onPairResultFromNotification(deviceId: String?, pairStatus: String): String? {
|
||||
assert(deviceId != null)
|
||||
if (pairStatus != PAIRING_PENDING) {
|
||||
BackgroundService.RunCommand(this) { service: BackgroundService ->
|
||||
val device = service.getDevice(deviceId)
|
||||
if (device == null) {
|
||||
Log.w(this::class.simpleName, "Reject pairing - device no longer exists: $deviceId")
|
||||
return@RunCommand
|
||||
}
|
||||
when (pairStatus) {
|
||||
PAIRING_ACCEPTED -> device.acceptPairing()
|
||||
PAIRING_REJECTED -> device.rejectPairing()
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (pairStatus == PAIRING_ACCEPTED || pairStatus == PAIRING_PENDING) deviceId else null
|
||||
}
|
||||
|
||||
private fun deviceIdToMenuEntryId(deviceId: String?): Int {
|
||||
for ((key, value) in mMapMenuToDeviceId) {
|
||||
if (value == deviceId) {
|
||||
return key.itemId
|
||||
}
|
||||
}
|
||||
return MENU_ENTRY_DEVICE_UNKNOWN
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == android.R.id.home) {
|
||||
mDrawerLayout?.openDrawer(mNavigationView)
|
||||
true
|
||||
} else {
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDeviceList() {
|
||||
BackgroundService.RunCommand(this@MainActivity) { service: BackgroundService ->
|
||||
val menu = mNavigationView.menu
|
||||
menu.clear()
|
||||
mMapMenuToDeviceId.clear()
|
||||
val devicesMenu = menu.addSubMenu(R.string.devices)
|
||||
var id = MENU_ENTRY_DEVICE_FIRST_ID
|
||||
val devices: Collection<Device> = service.devices.values
|
||||
for (device in devices) {
|
||||
if (device.isReachable && device.isPaired) {
|
||||
val item = devicesMenu.add(Menu.FIRST, id++, 1, device.name)
|
||||
item.setIcon(device.icon)
|
||||
item.setCheckable(true)
|
||||
mMapMenuToDeviceId[item] = device.deviceId
|
||||
}
|
||||
}
|
||||
val addDeviceItem = devicesMenu.add(Menu.FIRST, MENU_ENTRY_ADD_DEVICE, 1000, R.string.pair_new_device)
|
||||
addDeviceItem.setIcon(R.drawable.ic_action_content_add_circle_outline_32dp)
|
||||
addDeviceItem.setCheckable(true)
|
||||
val settingsItem = menu.add(Menu.FIRST, MENU_ENTRY_SETTINGS, 1000, R.string.settings)
|
||||
settingsItem.setIcon(R.drawable.ic_settings_white_32dp)
|
||||
settingsItem.setCheckable(true)
|
||||
val aboutItem = menu.add(Menu.FIRST, MENU_ENTRY_ABOUT, 1000, R.string.about)
|
||||
aboutItem.setIcon(R.drawable.ic_baseline_info_24)
|
||||
aboutItem.setCheckable(true)
|
||||
|
||||
//Ids might have changed
|
||||
if (mCurrentMenuEntry >= MENU_ENTRY_DEVICE_FIRST_ID) {
|
||||
mCurrentMenuEntry = deviceIdToMenuEntryId(mCurrentDevice)
|
||||
}
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
BackgroundService.RunCommand(this) { service: BackgroundService ->
|
||||
service.onNetworkChange()
|
||||
service.addDeviceListChangedCallback(this::class.simpleName) { updateDeviceList() }
|
||||
}
|
||||
updateDeviceList()
|
||||
onBackPressedDispatcher.addCallback(mainFragmentCallback)
|
||||
onBackPressedDispatcher.addCallback(closeDrawerCallback)
|
||||
if (mDrawerLayout == null) closeDrawerCallback.isEnabled = false
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
BackgroundService.RunCommand(this) { service: BackgroundService -> service.removeDeviceListChangedCallback(this::class.simpleName) }
|
||||
super.onStop()
|
||||
mainFragmentCallback.remove()
|
||||
closeDrawerCallback.remove()
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun onDeviceSelected(deviceId: String?, fromDeviceList: Boolean = false) {
|
||||
mCurrentDevice = deviceId
|
||||
preferences.edit().putString(STATE_SELECTED_DEVICE, deviceId).apply()
|
||||
if (mCurrentDevice != null) {
|
||||
mCurrentMenuEntry = deviceIdToMenuEntryId(deviceId)
|
||||
if (mCurrentMenuEntry == MENU_ENTRY_DEVICE_UNKNOWN) {
|
||||
uncheckAllMenuItems(mNavigationView.menu)
|
||||
} else {
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry)
|
||||
}
|
||||
setContentFragment(newInstance(deviceId, fromDeviceList))
|
||||
} else {
|
||||
mCurrentMenuEntry = MENU_ENTRY_ADD_DEVICE
|
||||
mNavigationView.setCheckedItem(mCurrentMenuEntry)
|
||||
setContentFragment(PairingFragment())
|
||||
}
|
||||
}
|
||||
|
||||
private fun setContentFragment(fragment: Fragment) {
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.container, fragment)
|
||||
.commit()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putString(STATE_SELECTED_DEVICE, mCurrentDevice)
|
||||
outState.putInt(STATE_SELECTED_MENU_ENTRY, mCurrentMenuEntry)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
when {
|
||||
requestCode == RESULT_NEEDS_RELOAD -> BackgroundService.RunCommand(this) { service: BackgroundService ->
|
||||
val device = service.getDevice(mCurrentDevice)
|
||||
device.reloadPluginsFromSettings()
|
||||
}
|
||||
|
||||
requestCode == STORAGE_LOCATION_CONFIGURED && resultCode == RESULT_OK && data != null -> {
|
||||
val uri = data.data
|
||||
ShareSettingsFragment.saveStorageLocationPreference(this, uri)
|
||||
}
|
||||
|
||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
val permissionsGranted = ArrayUtils.contains(grantResults, PackageManager.PERMISSION_GRANTED)
|
||||
if (permissionsGranted) {
|
||||
val i = ArrayUtils.indexOf(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
val writeStoragePermissionGranted = i != ArrayUtils.INDEX_NOT_FOUND &&
|
||||
grantResults[i] == PackageManager.PERMISSION_GRANTED
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && writeStoragePermissionGranted) {
|
||||
// To get a writeable path manually on Android 10 and later for Share and Receive Plugin.
|
||||
// Otherwise, Receiving files will keep failing until the user chooses a path manually to receive files.
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
startActivityForResult(intent, STORAGE_LOCATION_CONFIGURED)
|
||||
}
|
||||
|
||||
//New permission granted, reload plugins
|
||||
BackgroundService.RunCommand(this) { service: BackgroundService ->
|
||||
val device = service.getDevice(mCurrentDevice)
|
||||
device.reloadPluginsFromSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
if (DeviceHelper.KEY_DEVICE_NAME_PREFERENCE == key) {
|
||||
mNavViewDeviceName.text = DeviceHelper.getDeviceName(this)
|
||||
BackgroundService.RunCommand(this) { obj: BackgroundService -> obj.onNetworkChange() } //Re-send our identity packet
|
||||
}
|
||||
}
|
||||
|
||||
private fun uncheckAllMenuItems(menu: Menu) {
|
||||
val size = menu.size()
|
||||
for (i in 0 until size) {
|
||||
val item = menu.getItem(i)
|
||||
item.subMenu?.let { uncheckAllMenuItems(it) } ?: item.setChecked(false)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_DEVICE_ID = "deviceId"
|
||||
const val PAIR_REQUEST_STATUS = "pair_req_status"
|
||||
const val PAIRING_ACCEPTED = "accepted"
|
||||
const val PAIRING_REJECTED = "rejected"
|
||||
const val PAIRING_PENDING = "pending"
|
||||
const val RESULT_NEEDS_RELOAD = RESULT_FIRST_USER
|
||||
const val FLAG_FORCE_OVERVIEW = "forceOverview"
|
||||
}
|
||||
|
||||
private inner class DrawerToggle(drawerLayout: DrawerLayout) : ActionBarDrawerToggle(
|
||||
this, /* host Activity */
|
||||
drawerLayout, /* DrawerLayout object */
|
||||
R.string.open, /* "open drawer" description */
|
||||
R.string.close /* "close drawer" description */
|
||||
) {
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
super.onDrawerClosed(drawerView)
|
||||
closeDrawerCallback.isEnabled = false
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
super.onDrawerOpened(drawerView)
|
||||
closeDrawerCallback.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
42
src/org/kde/kdeconnect/UserInterface/compose/Buttons.kt
Normal file
42
src/org/kde/kdeconnect/UserInterface/compose/Buttons.kt
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Dmitry Yudin <dgyudin@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.UserInterface.compose
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun KdeTextButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier,
|
||||
text: String,
|
||||
enabled: Boolean = true,
|
||||
contentPadding: PaddingValues = PaddingValues(16.dp),
|
||||
iconLeft: ImageVector? = null,
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
contentPadding = contentPadding,
|
||||
content = {
|
||||
iconLeft?.let {
|
||||
Icon(imageVector = it, contentDescription = null)
|
||||
Spacer(Modifier.width(16.dp))
|
||||
}
|
||||
Text(text = text)
|
||||
}
|
||||
)
|
||||
}
|
41
src/org/kde/kdeconnect/UserInterface/compose/TextFields.kt
Normal file
41
src/org/kde/kdeconnect/UserInterface/compose/TextFields.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Dmitry Yudin <dgyudin@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.UserInterface.compose
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.kde.kdeconnect_tp.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun KdeTextField(modifier: Modifier = Modifier, input: MutableState<String>, label: String) {
|
||||
var value by rememberSaveable { input }
|
||||
OutlinedTextField(
|
||||
modifier = modifier,
|
||||
value = value,
|
||||
onValueChange = { userInput -> value = userInput },
|
||||
label = { Text(label) },
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("UnrememberedMutableState")
|
||||
@Preview
|
||||
@Composable
|
||||
fun Preview() {
|
||||
KdeTextField(
|
||||
input = mutableStateOf("John Doe"),
|
||||
label = stringResource(R.string.click_here_to_type),
|
||||
)
|
||||
}
|
33
src/org/kde/kdeconnect/UserInterface/compose/TopAppBars.kt
Normal file
33
src/org/kde/kdeconnect/UserInterface/compose/TopAppBars.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Dmitry Yudin <dgyudin@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
package org.kde.kdeconnect.UserInterface.compose
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun KdeTopAppBar(
|
||||
title: String,
|
||||
navIcon: ImageVector,
|
||||
navIconOnClick: () -> Unit,
|
||||
actions: @Composable (RowScope.() -> Unit) = {},
|
||||
) {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navIconOnClick, content = { Icon(navIcon, null) })
|
||||
},
|
||||
title = { Text(title) },
|
||||
actions = actions
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user