mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-09-02 07:05:09 +00:00
Update Presenter activity to use Compose
The Presenter activity including its layout file and related Java class were replaced with Compose UI. Additionally, the androidx.compose.material3:material3 was updated from version 1.1.0 to version 1.1.1.
This commit is contained in:
committed by
Albert Vaca Cintora
parent
ad83f76ad1
commit
c5c780b5ce
@@ -1,81 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
-->
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:context="org.kde.kdeconnect.Plugins.PresenterPlugin.PresenterActivity">
|
|
||||||
|
|
||||||
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/mpris_control_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@android:style/TextAppearance.Medium"
|
|
||||||
android:id="@+id/textView"
|
|
||||||
android:layout_weight="0"
|
|
||||||
android:layout_marginBottom="6dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/presenter_lock_tip" />
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_marginBottom="6dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_weight="1">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/previous_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:contentDescription="@string/mpris_rew"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:layout_marginEnd="3dp"
|
|
||||||
app:icon="@drawable/ic_previous_black"
|
|
||||||
style="@style/KdeConnectButton.IconButton" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/next_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_marginStart="3dp"
|
|
||||||
android:layout_weight="0.25"
|
|
||||||
android:contentDescription="@string/mpris_ff"
|
|
||||||
app:icon="@drawable/ic_next_black"
|
|
||||||
style="@style/KdeConnectButton.IconButton" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/pointer_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_marginBottom="6dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.30"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/presenter_pointer"
|
|
||||||
style="@style/KdeConnectButton.IconButton.Secondary"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
-->
|
|
||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/fullscreen"
|
|
||||||
android:title="@string/presenter_fullscreen" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/exit_presentation"
|
|
||||||
android:title="@string/presenter_exit" />
|
|
||||||
</menu>
|
|
@@ -15,9 +15,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
|
||||||
import androidx.compose.material.icons.filled.Send
|
import androidx.compose.material.icons.filled.Send
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -74,10 +72,10 @@ class ComposeSendActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
val plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin::class.java)
|
val plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin::class.java)
|
||||||
if (plugin == null) {
|
if (plugin == null) {
|
||||||
finish();
|
finish()
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
plugin.sendKeyboardPacket(np);
|
plugin.sendKeyboardPacket(np)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendComposed() {
|
private fun sendComposed() {
|
||||||
@@ -89,7 +87,6 @@ class ComposeSendActivity : AppCompatActivity() {
|
|||||||
userInput.value = String()
|
userInput.value = String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ComposeSendScreen() {
|
private fun ComposeSendScreen() {
|
||||||
Mdc3Theme {
|
Mdc3Theme {
|
||||||
@@ -97,7 +94,6 @@ class ComposeSendActivity : AppCompatActivity() {
|
|||||||
topBar = {
|
topBar = {
|
||||||
KdeTopAppBar(
|
KdeTopAppBar(
|
||||||
title = stringResource(R.string.compose_send_title),
|
title = stringResource(R.string.compose_send_title),
|
||||||
navIcon = Icons.Default.ArrowBack,
|
|
||||||
navIconOnClick = { onBackPressedDispatcher.onBackPressed() },
|
navIconOnClick = { onBackPressedDispatcher.onBackPressed() },
|
||||||
actions = {
|
actions = {
|
||||||
KdeTextButton(
|
KdeTextButton(
|
||||||
|
@@ -1,185 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2014 Ahmed I. Khalil <ahmedibrahimkhali@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kde.kdeconnect.Plugins.PresenterPlugin;
|
|
||||||
|
|
||||||
import android.hardware.Sensor;
|
|
||||||
import android.hardware.SensorEvent;
|
|
||||||
import android.hardware.SensorEventListener;
|
|
||||||
import android.hardware.SensorManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.support.v4.media.session.MediaSessionCompat;
|
|
||||||
import android.support.v4.media.session.PlaybackStateCompat;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.media.VolumeProviderCompat;
|
|
||||||
|
|
||||||
import org.kde.kdeconnect.KdeConnect;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityPresenterBinding;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class PresenterActivity extends AppCompatActivity implements SensorEventListener {
|
|
||||||
private ActivityPresenterBinding binding;
|
|
||||||
|
|
||||||
private MediaSessionCompat mMediaSession;
|
|
||||||
|
|
||||||
private PresenterPlugin plugin;
|
|
||||||
|
|
||||||
private SensorManager sensorManager;
|
|
||||||
|
|
||||||
static final float SENSITIVITY = 0.03f; //TODO: Make configurable?
|
|
||||||
|
|
||||||
public void gyroscopeEvent(SensorEvent event) {
|
|
||||||
float xPos = -event.values[2] * SENSITIVITY;
|
|
||||||
float yPos = -event.values[0] * SENSITIVITY;
|
|
||||||
|
|
||||||
plugin.sendPointer(xPos, yPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onSensorChanged(SensorEvent event) {
|
|
||||||
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
|
|
||||||
gyroscopeEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
|
||||||
//Ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
void enablePointer() {
|
|
||||||
if (sensorManager != null) {
|
|
||||||
return; //Already enabled
|
|
||||||
}
|
|
||||||
sensorManager = ContextCompat.getSystemService(this, SensorManager.class);
|
|
||||||
binding.pointerButton.setVisibility(View.VISIBLE);
|
|
||||||
binding.pointerButton.setOnTouchListener((v, event) -> {
|
|
||||||
if(event.getAction() == MotionEvent.ACTION_DOWN){
|
|
||||||
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME);
|
|
||||||
v.performClick(); // The linter complains if this is not called
|
|
||||||
}
|
|
||||||
else if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
||||||
sensorManager.unregisterListener(this);
|
|
||||||
plugin.stopPointer();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
binding = ActivityPresenterBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
|
|
||||||
setSupportActionBar(binding.toolbarLayout.toolbar);
|
|
||||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
|
||||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
|
||||||
|
|
||||||
String deviceId = getIntent().getStringExtra("deviceId");
|
|
||||||
this.plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, PresenterPlugin.class);
|
|
||||||
|
|
||||||
binding.nextButton.setOnClickListener(v -> plugin.sendNext());
|
|
||||||
binding.previousButton.setOnClickListener(v -> plugin.sendPrevious());
|
|
||||||
if (plugin.isPointerSupported()) {
|
|
||||||
enablePointer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
MenuInflater inflater = getMenuInflater();
|
|
||||||
inflater.inflate(R.menu.menu_presenter, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
int id = item.getItemId();
|
|
||||||
if (id == R.id.fullscreen) {
|
|
||||||
plugin.sendFullscreen();
|
|
||||||
return true;
|
|
||||||
} else if (id == R.id.exit_presentation) {
|
|
||||||
plugin.sendEsc();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return super.onContextItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
if (mMediaSession != null) {
|
|
||||||
mMediaSession.setActive(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
createMediaSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
|
|
||||||
if (sensorManager != null) {
|
|
||||||
// Make sure we don't leave the listener on
|
|
||||||
sensorManager.unregisterListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mMediaSession != null) {
|
|
||||||
PowerManager pm = ContextCompat.getSystemService(this, PowerManager.class);
|
|
||||||
boolean screenOn = pm.isInteractive();
|
|
||||||
if (screenOn) {
|
|
||||||
mMediaSession.release();
|
|
||||||
} // else we are in the lockscreen, keep the mediasession
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createMediaSession() {
|
|
||||||
mMediaSession = new MediaSessionCompat(this, "kdeconnect");
|
|
||||||
|
|
||||||
// Deprecated flags not required in Build.VERSION_CODES.O and later
|
|
||||||
mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
|
|
||||||
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
|
||||||
mMediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
|
|
||||||
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 0)
|
|
||||||
.build());
|
|
||||||
mMediaSession.setPlaybackToRemote(getVolumeProvider());
|
|
||||||
mMediaSession.setActive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private VolumeProviderCompat getVolumeProvider() {
|
|
||||||
final int VOLUME_UP = 1;
|
|
||||||
final int VOLUME_DOWN = -1;
|
|
||||||
return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, 1, 0) {
|
|
||||||
@Override
|
|
||||||
public void onAdjustVolume(int direction) {
|
|
||||||
if (direction == VOLUME_UP) {
|
|
||||||
plugin.sendNext();
|
|
||||||
}
|
|
||||||
else if (direction == VOLUME_DOWN) {
|
|
||||||
plugin.sendPrevious();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSupportNavigateUp() {
|
|
||||||
super.onBackPressed();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* 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.PresenterPlugin
|
||||||
|
|
||||||
|
import android.hardware.Sensor
|
||||||
|
import android.hardware.SensorEvent
|
||||||
|
import android.hardware.SensorEventListener
|
||||||
|
import android.hardware.SensorManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.PowerManager
|
||||||
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.ArrowForward
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInteropFilter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.media.VolumeProviderCompat
|
||||||
|
import com.google.accompanist.themeadapter.material3.Mdc3Theme
|
||||||
|
import org.kde.kdeconnect.KdeConnect
|
||||||
|
import org.kde.kdeconnect.UserInterface.compose.KdeButton
|
||||||
|
import org.kde.kdeconnect.UserInterface.compose.KdeTopAppBar
|
||||||
|
import org.kde.kdeconnect_tp.R
|
||||||
|
|
||||||
|
private const val VOLUME_UP = 1
|
||||||
|
private const val VOLUME_DOWN = -1
|
||||||
|
|
||||||
|
class PresenterActivity : AppCompatActivity(), SensorEventListener {
|
||||||
|
|
||||||
|
private val offScreenControlsSupported = Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
|
||||||
|
private val mediaSession by lazy {
|
||||||
|
if (offScreenControlsSupported) MediaSessionCompat(this, "kdeconnect") else null
|
||||||
|
}
|
||||||
|
private val powerManager by lazy { getSystemService(POWER_SERVICE) as PowerManager }
|
||||||
|
private val plugin: PresenterPlugin by lazy {
|
||||||
|
KdeConnect.getInstance().getDevicePlugin(intent.getStringExtra("deviceId"), PresenterPlugin::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: make configurable
|
||||||
|
private val sensitivity = 0.03f
|
||||||
|
override fun onSensorChanged(event: SensorEvent?) {
|
||||||
|
if (event?.sensor?.type == Sensor.TYPE_GYROSCOPE) {
|
||||||
|
val xPos = -event.values[2] * sensitivity
|
||||||
|
val yPos = -event.values[0] * sensitivity
|
||||||
|
|
||||||
|
plugin.sendPointer(xPos, yPos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
||||||
|
//ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContent { PresenterScreen() }
|
||||||
|
createMediaSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
mediaSession?.setActive(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
//fixme watch for isInteractive in background
|
||||||
|
mediaSession?.setActive(!powerManager.isInteractive)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
mediaSession?.release()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMediaSession() {
|
||||||
|
mediaSession?.setPlaybackState(
|
||||||
|
PlaybackStateCompat.Builder().setState(PlaybackStateCompat.STATE_PLAYING, 0, 0f).build()
|
||||||
|
)
|
||||||
|
mediaSession?.setPlaybackToRemote(volumeProvider)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private val volumeProvider = object : VolumeProviderCompat(VOLUME_CONTROL_RELATIVE, 1, 0) {
|
||||||
|
override fun onAdjustVolume(direction: Int) {
|
||||||
|
if (direction == VOLUME_UP) {
|
||||||
|
plugin.sendNext()
|
||||||
|
} else if (direction == VOLUME_DOWN) {
|
||||||
|
plugin.sendPrevious()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun PresenterScreen() {
|
||||||
|
|
||||||
|
val sensorManager = LocalContext.current.getSystemService(SENSOR_SERVICE) as? SensorManager
|
||||||
|
|
||||||
|
Mdc3Theme {
|
||||||
|
Scaffold(topBar = { PresenterAppBar() }) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize().padding(it).padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp),
|
||||||
|
) {
|
||||||
|
if (offScreenControlsSupported) Text(
|
||||||
|
text = stringResource(R.string.presenter_lock_tip),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp).padding(horizontal = 16.dp),
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxSize().weight(3f),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(20.dp),
|
||||||
|
) {
|
||||||
|
KdeButton(
|
||||||
|
onClick = { plugin.sendPrevious() },
|
||||||
|
modifier = Modifier.fillMaxSize().weight(1f),
|
||||||
|
icon = Icons.Default.ArrowBack,
|
||||||
|
)
|
||||||
|
KdeButton(
|
||||||
|
onClick = { plugin.sendNext() },
|
||||||
|
modifier = Modifier.fillMaxSize().weight(1f),
|
||||||
|
icon = Icons.Default.ArrowForward,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (sensorManager != null) KdeButton(
|
||||||
|
onClick = {},
|
||||||
|
colors = ButtonDefaults.filledTonalButtonColors(),
|
||||||
|
modifier = Modifier.fillMaxSize().weight(1f).pointerInteropFilter { event ->
|
||||||
|
when (event.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
sensorManager.registerListener(
|
||||||
|
this@PresenterActivity,
|
||||||
|
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
|
||||||
|
SensorManager.SENSOR_DELAY_GAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
sensorManager.unregisterListener(this@PresenterActivity)
|
||||||
|
plugin.stopPointer()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = stringResource(R.string.presenter_pointer),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun PresenterAppBar() {
|
||||||
|
|
||||||
|
var dropdownShownState by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
KdeTopAppBar(navIconOnClick = { onBackPressedDispatcher.onBackPressed() }, actions = {
|
||||||
|
IconButton(onClick = { dropdownShownState = true }) {
|
||||||
|
Icon(Icons.Default.MoreVert, stringResource(R.string.extra_options))
|
||||||
|
}
|
||||||
|
DropdownMenu(expanded = dropdownShownState, onDismissRequest = { dropdownShownState = false }) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = { plugin.sendFullscreen() },
|
||||||
|
text = { Text(stringResource(R.string.presenter_fullscreen)) },
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = { plugin.sendEsc() },
|
||||||
|
text = { Text(stringResource(R.string.presenter_exit)) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -9,12 +9,16 @@ package org.kde.kdeconnect.UserInterface.compose
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material.icons.filled.Build
|
||||||
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -39,4 +43,46 @@ fun KdeTextButton(
|
|||||||
Text(text = text)
|
Text(text = text)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun KdeButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||||
|
text: String? = null,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
) {
|
||||||
|
//TODO uncomment when button is widely used
|
||||||
|
// val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
// val pressedState = interactionSource.collectIsPressedAsState()
|
||||||
|
// val cornerSize by animateDpAsState(
|
||||||
|
// targetValue = if (pressedState.value) 24.dp else 48.dp,
|
||||||
|
// label = "Corner size change on press"
|
||||||
|
// )
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
// shape = RoundedCornerShape(cornerSize),
|
||||||
|
shape = RoundedCornerShape(24.dp),
|
||||||
|
colors = colors,
|
||||||
|
// interactionSource = interactionSource,
|
||||||
|
content = {
|
||||||
|
icon?.let { Icon(imageVector = it, contentDescription = text) }
|
||||||
|
text?.let { Text(it, maxLines = 1, overflow = Ellipsis) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun IconButtonPreview() {
|
||||||
|
KdeButton(
|
||||||
|
{},
|
||||||
|
Modifier.width(120.dp),
|
||||||
|
ButtonDefaults.buttonColors(Color.Gray, Color.DarkGray),
|
||||||
|
"Button Text",
|
||||||
|
Icons.Default.Build,
|
||||||
|
)
|
||||||
}
|
}
|
@@ -7,7 +7,6 @@
|
|||||||
package org.kde.kdeconnect.UserInterface.compose
|
package org.kde.kdeconnect.UserInterface.compose
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
@@ -17,7 +16,6 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun KdeTextField(modifier: Modifier = Modifier, input: MutableState<String>, label: String) {
|
fun KdeTextField(modifier: Modifier = Modifier, input: MutableState<String>, label: String) {
|
||||||
var value by rememberSaveable { input }
|
var value by rememberSaveable { input }
|
||||||
|
@@ -7,20 +7,20 @@
|
|||||||
package org.kde.kdeconnect.UserInterface.compose
|
package org.kde.kdeconnect.UserInterface.compose
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import org.kde.kdeconnect_tp.R
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun KdeTopAppBar(
|
fun KdeTopAppBar(
|
||||||
title: String,
|
title: String = stringResource(R.string.kde_connect),
|
||||||
navIcon: ImageVector,
|
navIcon: ImageVector = Icons.Default.ArrowBack,
|
||||||
navIconOnClick: () -> Unit,
|
navIconOnClick: () -> Unit, // = { onBackPressedDispatcher.onBackPressed() }
|
||||||
actions: @Composable (RowScope.() -> Unit) = {},
|
actions: @Composable (RowScope.() -> Unit) = {},
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
Reference in New Issue
Block a user