Skip to content

Commit

Permalink
[feature|fix|build] Support in-app selection of external media files …
Browse files Browse the repository at this point in the history
…for playback; fix bugs in FilePicker; update dependencies
  • Loading branch information
SkyD666 committed Jul 27, 2024
1 parent cf9b7ea commit 10b902d
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 31 deletions.
18 changes: 9 additions & 9 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ android {
minSdk = 24
targetSdk = 34
versionCode = 18
versionName = "1.1-beta56"
versionName = "1.1-beta57"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down Expand Up @@ -159,17 +159,17 @@ dependencies {

implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.activity:activity-ktx:1.9.0")
implementation("androidx.activity:activity-ktx:1.9.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
implementation("androidx.navigation:navigation-compose:2.7.7")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.3")
implementation("androidx.compose.ui:ui:1.7.0-beta05")
implementation("androidx.compose.material:material:1.7.0-beta05")
implementation("androidx.compose.material3:material3:1.3.0-beta04")
implementation("androidx.compose.material3:material3-window-size-class:1.3.0-beta04")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.4")
implementation("androidx.compose.ui:ui:1.7.0-beta06")
implementation("androidx.compose.material:material:1.7.0-beta06")
implementation("androidx.compose.material3:material3:1.3.0-beta05")
implementation("androidx.compose.material3:material3-window-size-class:1.3.0-beta05")
implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-beta04")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-beta04")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-beta04")
Expand All @@ -183,8 +183,8 @@ dependencies {
implementation("androidx.datastore:datastore-preferences:1.1.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.paging:paging-runtime-ktx:3.3.0")
implementation("androidx.paging:paging-compose:3.3.0")
implementation("androidx.paging:paging-runtime-ktx:3.3.1")
implementation("androidx.paging:paging-compose:3.3.1")
implementation("androidx.preference:preference-ktx:1.2.1")

implementation("com.google.android.material:material:1.12.0")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.skyd.anivu.ui.fragment.filepicker

import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand Down Expand Up @@ -66,6 +67,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import java.io.File


Expand All @@ -79,13 +81,15 @@ class FilePickerFragment : BaseComposeFragment() {
val path = arguments?.getString(PATH_KEY)
val pickFolder = arguments?.getBoolean(PICK_FOLDER_KEY)
val extensionName = arguments?.getString(EXTENSION_NAME_KEY)
val id = arguments?.getString(PICK_FOLDER_ID_KEY)
if (path == null || pickFolder == null || extensionName == null) {
findMainNavController().popBackStackWithLifecycle()
} else {
FilePickerScreen(
path = path,
pickFolder = pickFolder,
extensionName = extensionName,
id = id,
)
}
}
Expand All @@ -95,16 +99,21 @@ const val PATH_KEY = "path"
const val PICK_FOLDER_KEY = "pickFolder"
const val EXTENSION_NAME_KEY = "extensionName"
const val FILE_PICKER_NEW_PATH_KEY = "newPath"
const val PICK_FOLDER_ID_KEY = "id"

@Composable
fun ListenToFilePicker(onNewPath: CoroutineScope.(String) -> Unit) {
fun ListenToFilePicker(onNewPath: CoroutineScope.(FilePickerResult) -> Unit) {
val navController = LocalNavController.current
LaunchedEffect(Unit) {
navController.currentBackStackEntry?.savedStateHandle
?.getStateFlow<String?>(FILE_PICKER_NEW_PATH_KEY, null)
?.filterNotNull()
?.onEach { this.onNewPath(it) }
?.collect()
navController.currentBackStackEntry?.savedStateHandle?.apply {
getStateFlow<FilePickerResult?>(FILE_PICKER_NEW_PATH_KEY, null)
.filterNotNull()
.onEach {
onNewPath(it)
remove<FilePickerResult?>(FILE_PICKER_NEW_PATH_KEY)
}
.collect()
}
}
}

Expand All @@ -113,6 +122,7 @@ fun navigateToFilePicker(
path: String,
pickFolder: Boolean = true,
extensionName: String = "",
id: String? = null,
) {
navController.navigate(
R.id.action_to_file_picker_fragment,
Expand All @@ -125,16 +135,27 @@ fun navigateToFilePicker(
} else path
)
putString(EXTENSION_NAME_KEY, extensionName)
putString(PICK_FOLDER_ID_KEY, id)
}
)
}

@Parcelize
data class FilePickerResult(
val id: String?,
val path: String,
val pickFolder: Boolean,
val extensionName: String?,
val result: String,
) : Parcelable


@Composable
fun FilePickerScreen(
path: String,
pickFolder: Boolean = false,
extensionName: String? = null,
id: String?,
viewModel: FilePickerViewModel = hiltViewModel(),
) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
Expand Down Expand Up @@ -168,7 +189,14 @@ fun FilePickerScreen(
AniVuTopBar(
style = AniVuTopBarStyle.Small,
scrollBehavior = scrollBehavior,
title = { Text(text = stringResource(R.string.file_picker_screen_name)) },
title = {
Text(
text = stringResource(
if (pickFolder) R.string.file_picker_screen_open_folder
else R.string.file_picker_screen_open_file
)
)
},
navigationIcon = {
AniVuIconButton(
onClick = { navController.popBackStackWithLifecycle() },
Expand Down Expand Up @@ -211,7 +239,17 @@ fun FilePickerScreen(
if (!pickFolder) {
navController.previousBackStackEntry
?.savedStateHandle
?.set(FILE_PICKER_NEW_PATH_KEY, file.absolutePath)
?.set(
FILE_PICKER_NEW_PATH_KEY,
FilePickerResult(
id = id,
path = path,
pickFolder = false,
extensionName = extensionName,
result = file.absolutePath,
)
)
navController.popBackStackWithLifecycle()
}
}
},
Expand Down Expand Up @@ -243,7 +281,16 @@ fun FilePickerScreen(
onClick = {
navController.previousBackStackEntry
?.savedStateHandle
?.set(FILE_PICKER_NEW_PATH_KEY, uiState.path)
?.set(
FILE_PICKER_NEW_PATH_KEY,
FilePickerResult(
id = id,
path = path,
pickFolder = true,
extensionName = extensionName,
result = uiState.path,
)
)
navController.popBackStackWithLifecycle()
},
) {
Expand Down
60 changes: 52 additions & 8 deletions app/src/main/java/com/skyd/anivu/ui/fragment/media/MediaScreen.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.skyd.anivu.ui.fragment.media

import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
Expand All @@ -16,13 +17,16 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.FileOpen
import androidx.compose.material.icons.outlined.MyLocation
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material.icons.outlined.Workspaces
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Tab
Expand All @@ -37,19 +41,25 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.skyd.anivu.R
import com.skyd.anivu.base.mvi.getDispatcher
import com.skyd.anivu.ext.activity
import com.skyd.anivu.ext.isCompact
import com.skyd.anivu.ext.showSnackbarWithLaunchedEffect
import com.skyd.anivu.model.bean.MediaGroupBean
import com.skyd.anivu.model.preference.data.medialib.MediaLibLocationPreference
import com.skyd.anivu.ui.activity.PlayActivity
import com.skyd.anivu.ui.component.AniVuFloatingActionButton
import com.skyd.anivu.ui.component.AniVuIconButton
import com.skyd.anivu.ui.component.AniVuTopBar
Expand All @@ -63,6 +73,7 @@ import com.skyd.anivu.ui.fragment.media.list.MediaList
import com.skyd.anivu.ui.local.LocalNavController
import com.skyd.anivu.ui.local.LocalWindowSizeClass
import kotlinx.coroutines.launch
import java.io.File
import kotlin.math.min

const val MEDIA_SCREEN_ROUTE = "mediaScreen"
Expand All @@ -86,8 +97,15 @@ fun MediaScreen(path: String, viewModel: MediaViewModel = hiltViewModel()) {
val pagerState = rememberPagerState(pageCount = { uiState.groups.size })
var openEditGroupDialog by rememberSaveable { mutableStateOf<MediaGroupBean?>(value = null) }

ListenToFilePicker { newPath ->
MediaLibLocationPreference.put(context, this, newPath)
ListenToFilePicker { result ->
if (result.pickFolder) {
MediaLibLocationPreference.put(context, this, result.result)
} else {
PlayActivity.play(
context.activity,
File(result.result).toUri(),
)
}
}

Scaffold(
Expand Down Expand Up @@ -129,14 +147,40 @@ fun MediaScreen(path: String, viewModel: MediaViewModel = hiltViewModel()) {
)
},
floatingActionButton = {
AniVuFloatingActionButton(
onClick = { openEditGroupDialog = uiState.groups[pagerState.currentPage].first },
onSizeWithSinglePaddingChanged = { width, height ->
fabWidth = width
fabHeight = height
val density = LocalDensity.current
Column(
modifier = Modifier.onSizeChanged {
with(density) {
fabWidth = it.width.toDp() + 16.dp
fabHeight = it.height.toDp() + 16.dp
}
},
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.End
) {
Icon(imageVector = Icons.Outlined.Edit, contentDescription = null)
SmallFloatingActionButton(
onClick = {
navigateToFilePicker(
navController = navController,
path = path,
pickFolder = false,
)
},
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.secondary,
) {
Icon(
imageVector = Icons.Outlined.FileOpen,
contentDescription = stringResource(id = R.string.open_file),
)
}
AniVuFloatingActionButton(
onClick = {
openEditGroupDialog = uiState.groups[pagerState.currentPage].first
},
) {
Icon(imageVector = Icons.Outlined.Edit, contentDescription = null)
}
}
},
contentWindowInsets = WindowInsets.safeDrawing.run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ fun DataScreen(viewModel: DataViewModel = hiltViewModel()) {
val uiEvent by viewModel.singleEvent.collectAsStateWithLifecycle(initialValue = null)
val dispatch = viewModel.getDispatcher(startWith = DataIntent.Init)

ListenToFilePicker { newPath ->
MediaLibLocationPreference.put(context, this, newPath)
ListenToFilePicker { result ->
MediaLibLocationPreference.put(context, this, result.result)
}

Scaffold(
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/navigation/nav_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@
<fragment
android:id="@+id/file_picker_fragment"
android:name="com.skyd.anivu.ui.fragment.filepicker.FilePickerFragment"
android:label="@string/file_picker_screen_name" />
android:label="@string/file_picker_screen_open_file" />
<action
android:id="@+id/action_to_file_picker_fragment"
app:destination="@id/file_picker_fragment" />
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@
<string name="storage_permission_request_screen_rationale">没有存储权限无法运行应用程序,请授予权限。</string>
<string name="storage_permission_request_screen_title">AniVu 需要存储访问</string>
<string name="storage_permission_request_screen_request_permission">授予权限</string>
<string name="file_picker_screen_name">文件选择器</string>
<string name="file_picker_screen_open_file">打开文件</string>
<string name="file_picker_screen_open_folder">打开文件夹</string>
<string name="file_picker_screen_pick">选择此文件夹</string>
<string name="file_picker_screen_internal_storage">内部存储</string>
<string name="media_screen_delete_file_warning">删除此文件?</string>
Expand All @@ -305,6 +306,7 @@
<string name="player_config_screen_auto_pip">自动画中画</string>
<string name="player_config_screen_auto_pip_description">如果按下主页或最近任务按钮,则切换到画中画模式</string>
<string name="player_picture_in_picture">画中画</string>
<string name="open_file">打开文件</string>
<plurals name="feed_screen_read_all_result">
<item quantity="other">已读 %d 项</item>
</plurals>
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@
<string name="storage_permission_request_screen_rationale">Application can\'t be launched without storage permission, please grant the permission</string>
<string name="storage_permission_request_screen_title">AniVu requires storage access</string>
<string name="storage_permission_request_screen_request_permission">Request permission</string>
<string name="file_picker_screen_name">File picker</string>
<string name="file_picker_screen_open_file">Open file</string>
<string name="file_picker_screen_open_folder">Open a folder</string>
<string name="file_picker_screen_pick">Pick this folder</string>
<string name="file_picker_screen_internal_storage">Internal storage</string>
<string name="media_screen_delete_file_warning">Delete this file?</string>
Expand All @@ -312,6 +313,7 @@
<string name="player_config_screen_auto_pip">Auto PIP</string>
<string name="player_config_screen_auto_pip_description">Switch to PiP mode if the Home or Recents button is pressed</string>
<string name="player_picture_in_picture">Picture in picture</string>
<string name="open_file">Open file</string>
<plurals name="feed_screen_read_all_result">
<item quantity="one">Read %d item</item>
<item quantity="other">Read %d items</item>
Expand Down

0 comments on commit 10b902d

Please sign in to comment.