Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,15 @@ class FileBrowserViewModel(
viewModelScope.launch {
appModelObservable.value = appModelMapper.map(state = state, loading = true)
state.sourceNode?.apply {
// fixme when this is possible on both platforms - need a broader check
if (cuerCastPlayerWatcher.isWatching()) {
launchRemotePlayer(
cuerCastPlayerWatcher.remoteNode ?: throw IllegalStateException("No remote"),
cuerCastPlayerWatcher.screen ?: throw IllegalStateException("No remote screen")
)
} else {
remoteDialogLauncher.launchRemotesDialog({ remoteNode, screen ->
launchRemotePlayer(remoteNode, screen)
launchRemotePlayer(remoteNode, screen ?: throw IllegalStateException("No screen selected"))
})
}
appModelObservable.value = appModelMapper.map(state = state, loading = false)
Expand All @@ -101,7 +102,12 @@ class FileBrowserViewModel(
state.selectedFile ?: throw IllegalStateException(),
screen.index
)
castController.connectCuerCast(state.sourceNode, screen)
// todo check if already connected to remote node
// todo also check if the dialog has connected
if (!castController.isConnected()) {
// assumes here that sourecnode == targetnode
castController.connectCuerCast(state.sourceNode, screen)
}
remoteDialogLauncher.hideRemotesDialog()
appModelObservable.value = appModelMapper.map(state = state, loading = false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ object RemotesComposables {
}) {
Text(stringResource(R.string.menu_delete))
}
DropdownMenuItem(onClick = {
expanded = dispatchAndClose(view, OnActionSendTo(remote.domain))
}) {
Text(stringResource(R.string.menu_sendto))
}
// Divider()
// DropdownMenuItem(onClick = {
// expanded = dispatchAndClose(view, OnActionPlaylists(remote.domain))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@
value.node
)

is CuerSelectSendTo ->
remotesDialogLauncher.launchRemotesDialog(
{ remoteNodeDomain, screen ->
remotesMviView.dispatch(Event.OnActionSendToSelected(value.sendNode, remoteNodeDomain))

Check warning

Code scanning / detekt

Line detected that is longer than the defined maximum line length in the code style. Warning

Line detected that is longer than the defined maximum line length in the code style.
remotesDialogLauncher.hideRemotesDialog()
},
null
)

None -> Unit
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import uk.co.sentinelweb.cuer.domain.PlayerNodeDomain
import uk.co.sentinelweb.cuer.domain.RemoteNodeDomain

class RemotesDialogFragment(
private val selectedListener: (RemoteNodeDomain, PlayerNodeDomain.Screen) -> Unit,
private val selectedNode: RemoteNodeDomain?
private val selectedListener: (RemoteNodeDomain, PlayerNodeDomain.Screen?) -> Unit,
private val selectedNode: RemoteNodeDomain?,
private val isSelectNodeOnly: Boolean,
) : DialogFragment(), AndroidScopeComponent {

override val scope: Scope by fragmentScopeWithSource<RemotesDialogFragment>()
Expand All @@ -31,7 +32,7 @@ class RemotesDialogFragment(
private val compactPlayerScroll: CompactPlayerScroll by inject()

private var _binding: FragmentComposeBinding? = null
private val binding get() = _binding ?: throw IllegalStateException("BrowseFragment view not bound")
private val binding get() = _binding ?: throw IllegalStateException("RemotesDialogFragment view not bound")

init {
log.tag(this)
Expand Down Expand Up @@ -61,7 +62,12 @@ class RemotesDialogFragment(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.listener = selectedListener
selectedNode?.apply { viewModel.onNodeSelected(this) }
if (isSelectNodeOnly) {
viewModel.setSelectNodeOnly()
} else {
selectedNode
?.apply { viewModel.onNodeSelected(this) }
}
binding.composeView.setContent {
RemotesDialogComposeables.RemotesDialogUi(viewModel)
}
Expand Down Expand Up @@ -89,10 +95,11 @@ class RemotesDialogFragment(

companion object {
fun newInstance(
selected: (RemoteNodeDomain, PlayerNodeDomain.Screen) -> Unit,
selectedNode: RemoteNodeDomain?
selected: (RemoteNodeDomain, PlayerNodeDomain.Screen?) -> Unit,
selectedNode: RemoteNodeDomain?,
isSelectNodeOnly: Boolean
): RemotesDialogFragment {
return RemotesDialogFragment(selected, selectedNode)
return RemotesDialogFragment(selected, selectedNode, isSelectNodeOnly)
}

@JvmStatic
Expand All @@ -110,5 +117,4 @@ class RemotesDialogFragment(
}
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ class RemotesDialogLauncher(

private var dialogFragment: DialogFragment? = null
override fun launchRemotesDialog(
callback: (RemoteNodeDomain, PlayerNodeDomain.Screen) -> Unit,
node: RemoteNodeDomain?
callback: (RemoteNodeDomain, PlayerNodeDomain.Screen?) -> Unit,
node: RemoteNodeDomain?,
isSelectNodeOnly: Boolean
) {
dialogFragment = RemotesDialogFragment.newInstance(callback, node)
dialogFragment = RemotesDialogFragment.newInstance(callback, node, isSelectNodeOnly)
dialogFragment?.show(activity.supportFragmentManager, CAST_DIALOG_FRAGMENT_TAG)
}

Expand All @@ -27,4 +28,4 @@ class RemotesDialogLauncher(
companion object {
val CAST_DIALOG_FRAGMENT_TAG = "RemotesDialogFragment"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@
log.d(command.toString())
when (command) {
is PlayerContract.PlayerCommand.Load -> {
log.d("PlayerCommand.Load: $_currentVideoId != ${command.platformId} start:${command.startPosition}")
if (_currentVideoId != command.platformId) {
_player?.loadVideo(command.platformId, command.startPosition / 1000f)
log.d("PlayerCommand.Load: $_currentVideoId != ${command.item.media.platformId} start:${command.startPosition}")

Check warning

Code scanning / detekt

Line detected that is longer than the defined maximum line length in the code style. Warning

Line detected that is longer than the defined maximum line length in the code style.
if (_currentVideoId != command.item.media.platformId) {
_player?.loadVideo(command.item.media.platformId, command.startPosition / 1000f)

Check warning

Code scanning / detekt

Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers. Warning

This expression contains a magic number. Consider defining it to a well named constant.
_progressBar?.isVisible = true
} else {
_player?.play()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ class YoutubeFullScreenActivity : YouTubeBaseActivity(),
when (label) {
is Command -> label.command.let { command ->
when (command) {
is Load -> player.cueVideo(command.platformId, command.startPosition.toInt())
is Load -> player.cueVideo(command.item.media.platformId, command.startPosition.toInt())
is Play -> player.play()
is Pause -> player.pause()
is SkipBack -> player.seekToMillis(player.currentTimeMillis - command.ms)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<string name="menu_pin">Pin</string>
<string name="menu_share">Share</string>
<string name="menu_delete">Delete</string>
<string name="menu_sendto">Send to …</string>
<string name="menu_paste">Paste &amp; add</string>
<string name="menu_restart">Restart</string>
<string name="menu_settings">Settings</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ interface RemoteStatusInteractor {
remote: RemoteNodeDomain,
): NetResult<Boolean>

@Throws(Exception::class)
suspend fun sendTo(
messageType: AvailableMessage.MsgType,
remote: RemoteNodeDomain,
target: RemoteNodeDomain,
): NetResult<Boolean>

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,32 @@ class AvailableMessageMapper(
)
}

fun mapToMulticastMessage(remoteNode: RemoteNodeDomain): AvailableMessage.DeviceInfo {
return AvailableMessage.DeviceInfo(
id = remoteNode.id,
hostname = remoteNode.hostname,
deviceType = remoteNode.deviceType,
version = config.version,
ipAddress = remoteNode.ipAddress,
port = remoteNode.port,
device = remoteNode.device,
authType = mapAuthType(remoteNode.authType),
versionCode = config.versionCode,
)
}

private fun mapAuthType(authType: LocalNodeDomain.AuthConfig): AvailableMessage.AuthMethod = when (authType) {
is LocalNodeDomain.AuthConfig.Open -> AvailableMessage.AuthMethod.Open
is LocalNodeDomain.AuthConfig.Username -> AvailableMessage.AuthMethod.Username
is LocalNodeDomain.AuthConfig.Confirm -> AvailableMessage.AuthMethod.Confirm
}

private fun mapAuthType(authType: RemoteNodeDomain.AuthType): AvailableMessage.AuthMethod = when (authType) {
is RemoteNodeDomain.AuthType.Open -> AvailableMessage.AuthMethod.Open
is RemoteNodeDomain.AuthType.Username -> AvailableMessage.AuthMethod.Username
is RemoteNodeDomain.AuthType.Token -> AvailableMessage.AuthMethod.Confirm
}

fun mapFromMulticastMessage(
msg: AvailableMessage.DeviceInfo,
wifiState: WifiStateProvider.WifiState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ fun LocalNodeDomain.locator() = Locator(ipAddress, port)
fun Pair<String, Int>.http() = "http://$first:$second"
fun LocalNodeDomain.http() = "http://$ipAddress:$port"
fun RemoteNodeDomain.http() = "http://$ipAddress:$port"
fun Locator.http() = "http://$address:$port"

fun Pair<String, Int>.https() = "https://$first:$second"
fun LocalNodeDomain.https() = "https://$ipAddress:$port"
fun RemoteNodeDomain.https() = "https://$ipAddress:$port"
fun Locator.https() = "https://$address:$port"
1 change: 1 addition & 0 deletions hub/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
implementation(libs.kotlinxCoroutinesJdk8)
implementation(libs.ktorClientCore)
implementation(libs.ktorClientCio)
implementation(libs.kotlinxDatetime)
implementation(libs.batikTranscoder)
implementation(libs.multiplatformSettings)
implementation(libs.vlcj)
Expand Down
2 changes: 2 additions & 0 deletions hub/src/main/kotlin/uk/co/sentinelweb/cuer/hub/di/Modules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import uk.co.sentinelweb.cuer.hub.ui.player.cast.*
import uk.co.sentinelweb.cuer.hub.ui.player.vlc.VlcPlayerUiCoordinator
import uk.co.sentinelweb.cuer.hub.ui.preferences.PreferencesUiCoordinator
import uk.co.sentinelweb.cuer.hub.ui.remotes.RemotesUiCoordinator
import uk.co.sentinelweb.cuer.hub.ui.remotes.selector.RemotesDialogLauncher
import uk.co.sentinelweb.cuer.hub.util.permission.EmptyLocationPermissionLaunch
import uk.co.sentinelweb.cuer.hub.util.platform.getNodeDeviceType
import uk.co.sentinelweb.cuer.hub.util.platform.getOSData
Expand Down Expand Up @@ -80,6 +81,7 @@ object Modules {
PreferencesUiCoordinator.uiModule,
FilesUiCoordinator.uiModule,
VlcPlayerUiCoordinator.uiModule,
RemotesDialogLauncher.launcherModule,
)

private val resourcesModule = module {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import uk.co.caprica.vlcj.player.base.MediaPlayerEventAdapter
import uk.co.caprica.vlcj.player.base.State
import uk.co.caprica.vlcj.player.component.CallbackMediaPlayerComponent
import uk.co.sentinelweb.cuer.app.orchestrator.OrchestratorContract.Source.REMOTE
import uk.co.sentinelweb.cuer.app.ui.player.PlayerContract
import uk.co.sentinelweb.cuer.app.ui.player.PlayerContract.PlayerCommand.*
import uk.co.sentinelweb.cuer.app.ui.player.PlayerContract.View.Event.*
Expand All @@ -23,9 +24,14 @@
import uk.co.sentinelweb.cuer.core.providers.PlayerConfigProvider
import uk.co.sentinelweb.cuer.core.providers.TimeProvider
import uk.co.sentinelweb.cuer.core.wrapper.LogWrapper
import uk.co.sentinelweb.cuer.domain.MediaDomain.MediaTypeDomain.FILE
import uk.co.sentinelweb.cuer.domain.PlayerNodeDomain
import uk.co.sentinelweb.cuer.domain.PlayerStateDomain
import uk.co.sentinelweb.cuer.domain.PlayerStateDomain.*
import uk.co.sentinelweb.cuer.domain.PlaylistItemDomain
import uk.co.sentinelweb.cuer.remote.server.LocalRepository
import uk.co.sentinelweb.cuer.remote.server.http
import uk.co.sentinelweb.cuer.remote.server.locator
import java.awt.BorderLayout
import java.awt.BorderLayout.*
import java.awt.Color
Expand All @@ -42,6 +48,7 @@
private val folderListUseCase: GetFolderListUseCase,
private val showHideControls: VlcPlayerShowHideControls,
private val keyMap: VlcPlayerKeyMap,
private val localRepository: LocalRepository,
) : JFrame(), KoinComponent {

lateinit var mediaPlayerComponent: CallbackMediaPlayerComponent
Expand Down Expand Up @@ -395,11 +402,11 @@

fun playStateChanged(command: PlayerContract.PlayerCommand) = when (command) {
is Load -> {
command.platformId
.also { log.d("") }
.let { folderListUseCase.truncatedToFullFolderPath(it) }
command.item
.also { log.d("${it.media.platformId}") }
.let { mapPath(it) }
?.also { playItem(it) }
?: log.d("Cannot get full path ${command.platformId}")
?: log.d("Cannot get full path ${command.item.media.platformId}")
}

is Pause -> mediaPlayerComponent.mediaPlayer().controls().pause()
Expand All @@ -409,6 +416,16 @@
is SeekTo -> mediaPlayerComponent.mediaPlayer().controls().setTime(command.ms)
}.also { log.d("command:${command::class.java.simpleName}") }

private fun mapPath(item: PlaylistItemDomain) =
item
.takeIf { it.id != null && it.id?.source == REMOTE && it.id?.locator != null }
?.takeIf { localRepository.localNode.locator() != it.id?.locator }
?.takeIf { it.media.mediaType == FILE }
?.let { it.copy(media = it.media.copy(platformId = "${it.id?.locator?.http()}/video-stream/${it.media.platformId}")) }
?.media
?.platformId
?: folderListUseCase.truncatedToFullFolderPath(item.media.platformId)

fun updateTexts(texts: PlayerContract.View.Model.Texts) {
if (!this@VlcPlayerSwingWindow.isUndecorated) {
title = texts.title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ class VlcPlayerUiCoordinator(
coordinator = get(),
folderListUseCase = get(),
showHideControls = VlcPlayerShowHideControls(),
keyMap = VlcPlayerKeyMap()
keyMap = VlcPlayerKeyMap(),
localRepository = get()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import uk.co.sentinelweb.cuer.hub.ui.common.image.ImageEnumMapper
import uk.co.sentinelweb.cuer.hub.ui.common.image.ImageFromUrl
import uk.co.sentinelweb.cuer.hub.ui.common.image.ImageSvg
import uk.co.sentinelweb.cuer.hub.ui.local.LocalComposables
import uk.co.sentinelweb.cuer.hub.ui.remotes.selector.RemotesDialogLauncherComposeables.ShowRemotesDialogIfNecessary
import uk.co.sentinelweb.cuer.remote.server.ServerState

object RemotesComposables {
Expand All @@ -38,6 +39,7 @@ object RemotesComposables {
fun RemotesUi(coordinator: RemotesUiCoordinator) {
val state = coordinator.modelObservable.collectAsState(initial = blankModel())
RemotesView(state.value, coordinator)
ShowRemotesDialogIfNecessary(coordinator.remotesDialogLauncher)
}

@Composable
Expand Down Expand Up @@ -232,6 +234,11 @@ object RemotesComposables {
}) {
Text("Delete")
}
DropdownMenuItem(onClick = {
expanded = dispatchAndClose(view, Event.OnActionSendTo(remote.domain))
}) {
Text("Send To ...")
}
Divider()
DropdownMenuItem(onClick = {
expanded = dispatchAndClose(view, Event.OnActionPlaylists(remote.domain))
Expand All @@ -250,4 +257,4 @@ object RemotesComposables {
view.dispatch(event)
return false
}
}
}
Loading
Loading