Skip to content

Commit

Permalink
Merge pull request #21 from kaleidot725/develop/v1.6.0
Browse files Browse the repository at this point in the history
Release v1.6.0 : Add scrcpy options
  • Loading branch information
kaleidot725 authored Mar 18, 2022
2 parents 4a13668 + d5096a7 commit fc2a4ee
Show file tree
Hide file tree
Showing 30 changed files with 488 additions and 182 deletions.
2 changes: 1 addition & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# 🐻‍❄️ ScrcpyHub

ScrcpyHub is a GUI application to mirror android screens.
ScrcpyHub uses [scrcpy](https://github.com/Genymobile/scrcpy). [scrcpy](https://github.com/Genymobile/scrcpy) is a mirroring android command tool.
ScrcpyHub uses [scrcpy](https://github.com/Genymobile/scrcpy). [scrcpy](https://github.com/Genymobile/scrcpy) is a
mirroring android command tool.

![demo](docs/demo.gif)

# ✨ Feature

- Support Windows10/11, Linux, macOS. 🖥️
- Support Windows10/11, Linux, macOS. 🖥️

- Support light theme and dark theme. 🖼️

Expand All @@ -21,17 +22,14 @@ ScrcpyHub uses [scrcpy](https://github.com/Genymobile/scrcpy). [scrcpy](https://

- Support Tary Menu. 📥


<img src="docs/5.png" width=256 hspace="5"><img src="docs/6.png" width=256 hspace="5"><img src="docs/1.png" width=256 hspace="5"><img src="docs/2.png" width=256 hspace="5"><img src="docs/3.png" width=256 hspace="5"><img src="docs/4.png" width=256 hspace="5"><img src=docs/tray.png width=256 hspace=5>

# ⬇️ Install

Install adb and scrcpy, ScrcpyHub.

## 💻 Windows 10/11

1. Download [here](https://github.com/Genymobile/scrcpy#windows) and install scrcpy somewhere.
2. Download [here](https://github.com/kaleidot725/scrcpy-hub/releases/tag/v1.5.1) and launch ScrcpyHub.
2. Download [here](https://github.com/kaleidot725/scrcpy-hub/releases/tag/v1.6.0) and launch ScrcpyHub.
3. Open ScrcpyHub Preferences.
4. Input adb and scrcpy location, save settings.

Expand All @@ -42,7 +40,7 @@ ScrcpyHub doesn't work mirroring start and stop if you install scrcpy through Ch
## 💻 Linux(Ubuntu)

1. Download [here](https://github.com/Genymobile/scrcpy#windows) and install scrcpy somewhere.
2. Download [here](https://github.com/kaleidot725/scrcpy-hub/releases/tag/v1.5.1) and install ScrcpHub.
2. Download [here](https://github.com/kaleidot725/scrcpy-hub/releases/tag/v1.6.0) and install ScrcpHub.

```
sudo dpkg -i scrcpyhub_1.5.1_amd64.deb
Expand All @@ -64,11 +62,11 @@ sudo dpkg -i scrcpyhub_1.5.1_amd64.deb
brew install android-platform-tools
brew install scrcpy
```
2. Download [here](https://github.com/kaleidot725/scrcpy-hub/releases/tag/v1.5.1) and launch ScrcpyHub.

2. Download [here](https://github.com/kaleidot725/scrcpy-hub/releases/tag/v1.6.0) and launch ScrcpyHub.
3. Open ScrcpyHub Preferences.
4. Input adb and scrcpy location, save settings.


# 🎫 Licence

The GNU General Public License v3.0 (GPLv3)
7 changes: 4 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat

group = "me.kaleidot725"
version = "1.5.1"
version = "1.6.0"

plugins {
kotlin("jvm") version "1.6.10"
kotlin("plugin.serialization") version "1.6.10"

id("org.jetbrains.compose") version "1.0.1"
id("org.jlleitschuh.gradle.ktlint") version "10.2.1"
}
Expand All @@ -27,8 +28,8 @@ dependencies {
implementation("com.github.Dansoftowner:jSystemThemeDetector:3.6")

testImplementation(kotlin("test-junit5"))
testImplementation("io.kotest:kotest-runner-junit5:5.0.3")
testImplementation("io.mockk:mockk:1.12.1")
testImplementation("io.mockk:mockk:1.12.3")
testImplementation("io.kotest:kotest-runner-junit5:5.1.0")
}

tasks.test {
Expand Down
Binary file removed docs/1.png
Binary file not shown.
Binary file removed docs/2.png
Binary file not shown.
Binary file removed docs/3.png
Binary file not shown.
Binary file removed docs/4.png
Binary file not shown.
Binary file removed docs/5.png
Binary file not shown.
Binary file removed docs/6.png
Binary file not shown.
Binary file removed docs/tray.png
Binary file not shown.
9 changes: 9 additions & 0 deletions src/main/kotlin/model/command/AdbCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,13 @@ class AdbCommand(private val factory: AdbCommandCreator) {
false
}
}

fun startAdbServer(): Boolean {
return try {
ProcessBuilder(factory.createStartServer()).start()
true
} catch (e: Exception) {
false
}
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/model/command/creator/AdbCommandCreator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ class AdbCommandCreator(
}
}

fun createStartServer(): List<String> {
return buildList {
if (path != null) {
if (path.endsWith(File.separator)) {
add("$path$COMMAND_NAME")
} else {
add("$path${File.separator}$COMMAND_NAME")
}
} else {
add(COMMAND_NAME)
}
add(START_SERVER)
}
}

fun createHelp(): List<String> {
return buildList {
if (path != null) {
Expand All @@ -37,5 +52,6 @@ class AdbCommandCreator(
companion object {
private const val COMMAND_NAME = "adb"
private const val HELP_OPTION = "--help"
private const val START_SERVER = "start-server"
}
}
38 changes: 19 additions & 19 deletions src/main/kotlin/model/command/creator/ScrcpyCommandCreator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,27 @@ class ScrcpyCommandCreator(val path: String? = null) {
add(MAX_SIZE_OPTION_NAME)
add(maxSize.toString())
}
}
}

fun createRecord(context: Device.Context, fileName: String): List<String> {
return buildList {
if (path != null) {
if (path.endsWith(File.separator)) {
add("$path$COMMAND_NAME")
} else {
add("$path${File.separator}$COMMAND_NAME")
}
} else {
add(COMMAND_NAME)
val maxFrameRate = context.maxFrameRate
if (maxFrameRate != null) {
add(MAX_FRAME_RATE_OPTION_NAME)
add(maxFrameRate.toString())
}

add(DEVICE_OPTION_NAME)
add(context.device.id)

val maxSize = context.maxSize
if (maxSize != null) {
add(MAX_SIZE_OPTION_NAME)
add(maxSize.toString())
val bitrate = context.bitrate
if (bitrate != null) {
add(BITRATE_OPTION_NAME)
add(bitrate.toString() + "M")
}

add(WINDOW_TITLE_OPTION_NAME)
add(context.displayName)
}
}

fun createRecord(context: Device.Context, fileName: String): List<String> {
return buildList {
addAll(create(context))
add(RECORD_OPTION_NAME)
add(fileName)
}
Expand All @@ -74,5 +71,8 @@ class ScrcpyCommandCreator(val path: String? = null) {
private const val MAX_SIZE_OPTION_NAME = "-m"
private const val HELP_OPTION_NAME = "-h"
private const val RECORD_OPTION_NAME = "-r"
private const val MAX_FRAME_RATE_OPTION_NAME = "--max-fps"
private const val BITRATE_OPTION_NAME = "-b"
private const val WINDOW_TITLE_OPTION_NAME = "--window-title"
}
}
11 changes: 8 additions & 3 deletions src/main/kotlin/model/di/Module.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ import model.usecase.GetScrcpyStatusUseCase
import model.usecase.GetSystemDarkModeFlowUseCase
import model.usecase.IsSetupCompletedUseCase
import model.usecase.SaveScreenshotToDesktopUseCase
import model.usecase.StartAdbServerUseCase
import model.usecase.StartScrcpyRecordUseCase
import model.usecase.StartScrcpyUseCase
import model.usecase.StopScrcpyRecordUseCase
import model.usecase.StopScrcpyUseCase
import model.usecase.UpdateDeviceNameUseCase
import model.usecase.UpdateDeviceSetting
import model.usecase.UpdateSettingUseCase
import org.koin.dsl.module
import viewmodel.DevicePageViewModel
Expand Down Expand Up @@ -79,6 +80,10 @@ val appModule = module {
GetDevicesFlowUseCase(get())
}

factory {
StartAdbServerUseCase(get())
}

factory {
FetchSettingUseCase(get())
}
Expand Down Expand Up @@ -108,7 +113,7 @@ val appModule = module {
}

factory {
UpdateDeviceNameUseCase(get())
UpdateDeviceSetting(get())
}

factory {
Expand All @@ -128,7 +133,7 @@ val appModule = module {
}

factory {
DevicesPageViewModel(get(), get(), get(), get(), get(), get(), get(), get())
DevicesPageViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get())
}

factory { (context: Device.Context) ->
Expand Down
4 changes: 3 additions & 1 deletion src/main/kotlin/model/entity/Device.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ data class Device(val id: String = "", val name: String = "") {
data class Context(
val device: Device,
val customName: String? = null,
val maxSize: Int? = null
val maxSize: Int? = null,
val maxFrameRate: Int? = null,
val bitrate: Int? = null
) {
val displayName get() = customName ?: device.name
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/model/usecase/GetDevicesFlowUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import model.entity.Device
import model.repository.DeviceRepository

class GetDevicesFlowUseCase(private val deviceRepository: DeviceRepository) {
fun get(scope: CoroutineScope): Flow<List<Device.Context>> {
suspend fun get(scope: CoroutineScope): Flow<List<Device.Context>> {
deviceRepository.getAll()
return deviceRepository.getAllFlow(scope)
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/model/usecase/StartAdbServerUseCase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package model.usecase

import model.command.AdbCommand
import model.command.creator.AdbCommandCreator
import model.repository.SettingRepository

class StartAdbServerUseCase(private val settingRepository: SettingRepository) {
suspend operator fun invoke(): Boolean {
val setting = settingRepository.get()
val adbCommand = AdbCommand(AdbCommandCreator(setting.adbLocation))
return adbCommand.startAdbServer()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package model.usecase
import model.entity.Device
import model.repository.DeviceRepository

class UpdateDeviceNameUseCase(private val deviceRepository: DeviceRepository) {
class UpdateDeviceSetting(private val deviceRepository: DeviceRepository) {
suspend fun execute(newContext: Device.Context): Boolean {
return try {
deviceRepository.saveDeviceSetting(newContext)
Expand Down
12 changes: 8 additions & 4 deletions src/main/kotlin/resource/Strings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package resource

object Strings {
// COMMON
const val APP_VERSION = "1.5.1"
const val APP_VERSION = "1.6.0"
const val APP_NAME = "ScrcpyHub"
const val SAVE = "Save"
const val SETUP = "Setup"
Expand Down Expand Up @@ -30,9 +30,13 @@ object Strings {

// Device Page
const val DEVICE_PAGE_EDIT_NAME_TITLE = "Device Name"
const val DEVICE_PAGE_EDIT_NAME_DETAILS = "Display device name"
const val DEVICE_PAGE_EDIT_MAX_SIZE_TITLE = "Max Size"
const val DEVICE_PAGE_EDIT_MAX_SIZE_DETAILS = "Video width and height size limit"
const val DEVICE_PAGE_EDIT_NAME_DETAILS = "Customize device name"
const val DEVICE_PAGE_EDIT_MAX_SIZE_TITLE = "Max Video Size"
const val DEVICE_PAGE_EDIT_MAX_SIZE_DETAILS = "Set video width and height limit"
const val DEVICE_PAGE_EDIT_MAX_FRAME_RATE_TITLE = "FPS (frame per second)"
const val DEVICE_PAGE_EDIT_MAX_FRAME_RATE_DETAILS = "Set video fps limit"
const val DEVICE_PAGE_EDIT_MAX_BITRATE_TITLE = "Bitrate (Mbps)"
const val DEVICE_PAGE_EDIT_MAX_BITRATE_DETAILS = "Set video bitrate limit"

// Setting Page
const val SETTING_PAGE_TITLE = "Preferences"
Expand Down
1 change: 0 additions & 1 deletion src/main/kotlin/view/components/molecules/PageHeader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ fun PageHeader(windowScope: WindowScope, title: String, optionContent: @Composab
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.padding(bottom = 8.dp)
.background(Color(red = 51, blue = 51, green = 51))
.padding(8.dp)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import androidx.compose.ui.unit.dp
import view.components.atoms.Texts

@Composable
fun TitleAndTextField(
fun TitlesAndTextField(
subtitle1: String,
subtitle2: String,
inputText: String,
Expand All @@ -22,6 +22,7 @@ fun TitleAndTextField(
Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp)) {
Texts.Subtitle1(subtitle1)
Texts.Subtitle2(subtitle2)

TextField(
value = inputText,
modifier = Modifier.fillMaxWidth(),
Expand All @@ -37,8 +38,8 @@ fun TitleAndTextField(

@Preview
@Composable
private fun DeviceNameSetting_Preview() {
TitleAndTextField(
private fun TitlesAndTextField_Preview() {
TitlesAndTextField(
subtitle1 = "SUBTITLE1",
subtitle2 = "SUBTITLE2",
inputText = "INPUT TEXT",
Expand Down
Loading

0 comments on commit fc2a4ee

Please sign in to comment.