2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-31 06:05:12 +00:00

Modernize ComposeSendActivity

* UI update for the old compose send screen.
* Introduces Jetpack Compose.
* Migrates activity to Kotlin.
* Fixes "send" button being next to "clear".
This commit is contained in:
Dmitry Yudin
2023-04-26 20:16:08 +00:00
committed by Albert Vaca Cintora
parent 921d0ee884
commit e9bc90d91a
27 changed files with 291 additions and 219 deletions

View File

@@ -275,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" />

View File

@@ -29,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
@@ -139,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'

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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"/>

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -488,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[

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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,
)
}
}
}
}
}

View File

@@ -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;
@@ -455,7 +453,6 @@ public class MousePadActivity
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();

View 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)
}
)
}

View 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),
)
}

View 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
)
}