Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update detekt to v1.22.0 #895

Merged
merged 5 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion app/src/main/java/org/jellyfin/mobile/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ class MainActivity : AppCompatActivity() {
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
} else super.onBackPressed()
} else {
super.onBackPressed()
}
}

override fun onDestroy() {
Expand Down
11 changes: 8 additions & 3 deletions app/src/main/java/org/jellyfin/mobile/app/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import org.koin.dsl.module
import java.util.concurrent.Executors

const val PLAYER_EVENT_CHANNEL = "PlayerEventChannel"
private const val HTTP_CACHE_SIZE: Long = 16 * 1024 * 1024
private const val TS_SEARCH_PACKETS = 1800

val applicationModule = module {
Expand Down Expand Up @@ -90,11 +91,15 @@ val applicationModule = module {
.enableHttp2(true)
.enableQuic(true)
.enableBrotli(true)
.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY, 16 * 1024 * 1024)
.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY, HTTP_CACHE_SIZE)
.build()
CronetDataSource.Factory(cronetEngine, Executors.newCachedThreadPool()).setUserAgent(Util.getUserAgent(context, Constants.APP_INFO_NAME))
CronetDataSource.Factory(cronetEngine, Executors.newCachedThreadPool()).apply {
setUserAgent(Util.getUserAgent(context, Constants.APP_INFO_NAME))
}
} else {
DefaultHttpDataSource.Factory().setUserAgent(Util.getUserAgent(context, Constants.APP_INFO_NAME))
DefaultHttpDataSource.Factory().apply {
setUserAgent(Util.getUserAgent(context, Constants.APP_INFO_NAME))
}
}

DefaultDataSource.Factory(context, baseDataSourceFactory)
Expand Down
15 changes: 4 additions & 11 deletions app/src/main/java/org/jellyfin/mobile/app/AppPreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,6 @@ class AppPreferences(context: Context) {
}
}

@Deprecated(message = "Deprecated in favor of SQLite database - only kept for migration reasons")
var instanceUrl: String?
get() = sharedPreferences.getString(Constants.PREF_INSTANCE_URL, null)
set(value) {
sharedPreferences.edit {
if (value != null) putString(Constants.PREF_INSTANCE_URL, value) else remove(Constants.PREF_INSTANCE_URL)
}
}

var ignoreBatteryOptimizations: Boolean
get() = sharedPreferences.getBoolean(Constants.PREF_IGNORE_BATTERY_OPTIMIZATIONS, false)
set(value) {
Expand All @@ -58,8 +49,10 @@ class AppPreferences(context: Context) {
var downloadMethod: Int?
get() = sharedPreferences.getInt(Constants.PREF_DOWNLOAD_METHOD, -1).takeIf { it >= 0 }
set(value) {
if (value != null) sharedPreferences.edit {
putInt(Constants.PREF_DOWNLOAD_METHOD, value)
if (value != null) {
sharedPreferences.edit {
putInt(Constants.PREF_DOWNLOAD_METHOD, value)
}
}
}

Expand Down
42 changes: 33 additions & 9 deletions app/src/main/java/org/jellyfin/mobile/bridge/ExternalPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ class ExternalPlayer(
private val apiClient: ApiClient = get()
private val videosApi: VideosApi = apiClient.videosApi

private val playerContract = registry.register("externalplayer", lifecycleOwner, ActivityResultContracts.StartActivityForResult()) { result ->
private val playerContract = registry.register(
"externalplayer",
lifecycleOwner,
ActivityResultContracts.StartActivityForResult(),
) { result ->
val resultCode = result.resultCode
val intent = result.data
when (val action = intent?.action) {
Expand Down Expand Up @@ -121,6 +125,7 @@ class ExternalPlayer(
return subtitleProfiles.toString()
}

@Suppress("LongMethod")
private fun playMediaSource(playOptions: PlayOptions, source: JellyfinMediaSource) {
val sourceInfo = source.sourceInfo
val url = when (source.playMethod) {
Expand Down Expand Up @@ -150,7 +155,10 @@ class ExternalPlayer(
}

// Select correct subtitle
val selectedSubtitleIndex = source.subtitleStreams.binarySearchBy(playOptions.subtitleStreamIndex, selector = MediaStream::index)
val selectedSubtitleIndex = source.subtitleStreams.binarySearchBy(
playOptions.subtitleStreamIndex,
selector = MediaStream::index,
)
source.selectSubtitleStream(selectedSubtitleIndex)

// Build playback intent
Expand All @@ -175,7 +183,10 @@ class ExternalPlayer(
}

// MX Player API / MPV
putExtra("subs", externalSubs.map { stream -> Uri.parse(apiClient.createUrl(stream.deliveryUrl)) }.toTypedArray())
val subtitleUris = externalSubs.map { stream ->
Uri.parse(apiClient.createUrl(stream.deliveryUrl))
}
putExtra("subs", subtitleUris.toTypedArray())
putExtra("subs.name", externalSubs.map(ExternalSubtitleStream::displayTitle).toTypedArray())
putExtra("subs.filename", externalSubs.map(ExternalSubtitleStream::language).toTypedArray())
putExtra("subs.enable", enabledSubUrl?.let { url -> arrayOf(Uri.parse(url)) } ?: emptyArray())
Expand All @@ -184,7 +195,10 @@ class ExternalPlayer(
if (enabledSubUrl != null) putExtra("subtitles_location", enabledSubUrl)
}
playerContract.launch(playerIntent)
Timber.d("Starting playback [id=${source.itemId}, title=${source.name}, playMethod=${source.playMethod}, startTimeMs=${source.startTimeMs}]")
Timber.d(
"Starting playback [id=${source.itemId}, title=${source.name}, " +
"playMethod=${source.playMethod}, startTimeMs=${source.startTimeMs}]",
)
}

private fun notifyEvent(event: String, parameters: String = "") {
Expand Down Expand Up @@ -278,7 +292,9 @@ class ExternalPlayer(
val extraPosition = data.getLongExtra("extra_position", 0L)
val extraDuration = data.getLongExtra("extra_duration", 0L)
if (extraPosition > 0L) {
Timber.d("Playback stopped [player=$player, extraPosition=$extraPosition, extraDuration=$extraDuration]")
Timber.d(
"Playback stopped [player=$player, extraPosition=$extraPosition, extraDuration=$extraDuration]",
)
notifyEvent(Constants.EVENT_TIME_UPDATE, "$extraPosition")
notifyEvent(Constants.EVENT_ENDED)
} else {
Expand All @@ -287,7 +303,9 @@ class ExternalPlayer(
notifyEvent(Constants.EVENT_TIME_UPDATE)
notifyEvent(Constants.EVENT_ENDED)
} else {
Timber.d("Invalid state [player=$player, extraPosition=$extraPosition, extraDuration=$extraDuration]")
Timber.d(
"Invalid state [player=$player, extraPosition=$extraPosition, extraDuration=$extraDuration]",
)
notifyEvent(Constants.EVENT_CANCELED)
context.toast(R.string.external_player_unknown_error, Toast.LENGTH_LONG)
}
Expand All @@ -306,9 +324,15 @@ class ExternalPlayer(
*/
private fun getComponent(@ExternalPlayerPackage packageName: String): ComponentName? {
return when (packageName) {
ExternalPlayerPackage.MPV_PLAYER -> ComponentName(packageName, "$packageName.MPVActivity")
ExternalPlayerPackage.MX_PLAYER_FREE, ExternalPlayerPackage.MX_PLAYER_PRO -> ComponentName(packageName, "$packageName.ActivityScreen")
ExternalPlayerPackage.VLC_PLAYER -> ComponentName(packageName, "$packageName.gui.video.VideoPlayerActivity")
ExternalPlayerPackage.MPV_PLAYER -> {
ComponentName(packageName, "$packageName.MPVActivity")
}
ExternalPlayerPackage.MX_PLAYER_FREE, ExternalPlayerPackage.MX_PLAYER_PRO -> {
ComponentName(packageName, "$packageName.ActivityScreen")
}
ExternalPlayerPackage.VLC_PLAYER -> {
ComponentName(packageName, "$packageName.gui.video.VideoPlayerActivity")
}
else -> null
}
}
Expand Down
12 changes: 7 additions & 5 deletions app/src/main/java/org/jellyfin/mobile/data/dao/UserDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ interface UserDao {

@Transaction
fun upsert(serverId: Long, userId: String, accessToken: String?): Long {
val user = getByUserId(serverId, userId)
return if (user != null) {
update(user.id, accessToken)
user.id
} else insert(serverId, userId, accessToken)
return when (val user = getByUserId(serverId, userId)) {
null -> insert(serverId, userId, accessToken)
else -> {
update(user.id, accessToken)
user.id
}
}
}

@Transaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ import org.jellyfin.mobile.data.entity.ServerEntity.Key.TABLE_NAME
@Parcelize
@Entity(tableName = TABLE_NAME, indices = [Index(value = arrayOf(HOSTNAME), unique = true)])
data class ServerEntity(
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = ID) val id: Long,
@ColumnInfo(name = HOSTNAME) val hostname: String,
@ColumnInfo(name = LAST_USED_TIMESTAMP) val lastUsedTimestamp: Long,
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = ID)
val id: Long,
@ColumnInfo(name = HOSTNAME)
val hostname: String,
@ColumnInfo(name = LAST_USED_TIMESTAMP)
val lastUsedTimestamp: Long,
) : Parcelable {
constructor(hostname: String) : this(0, hostname, System.currentTimeMillis())

Expand Down
19 changes: 13 additions & 6 deletions app/src/main/java/org/jellyfin/mobile/data/entity/UserEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@ import org.jellyfin.mobile.data.entity.UserEntity.Key.USER_ID
],
)
data class UserEntity(
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = ID) val id: Long,
@ColumnInfo(name = SERVER_ID) val serverId: Long,
@ColumnInfo(name = USER_ID) val userId: String,
@ColumnInfo(name = ACCESS_TOKEN) val accessToken: String?,
@ColumnInfo(name = LAST_LOGIN_TIMESTAMP) val lastLoginTimestamp: Long,
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = ID)
val id: Long,
@ColumnInfo(name = SERVER_ID)
val serverId: Long,
@ColumnInfo(name = USER_ID)
val userId: String,
@ColumnInfo(name = ACCESS_TOKEN)
val accessToken: String?,
@ColumnInfo(name = LAST_LOGIN_TIMESTAMP)
val lastLoginTimestamp: Long,
) {
constructor(serverId: Long, userId: String, accessToken: String?) : this(0, serverId, userId, accessToken, System.currentTimeMillis())
constructor(serverId: Long, userId: String, accessToken: String?) :
this(0, serverId, userId, accessToken, System.currentTimeMillis())

companion object Key {
const val TABLE_NAME = "User"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ class ActivityEventHandler(
event.args,
object : JavascriptCallback() {
override fun callback(keep: Boolean, err: String?, result: String?) {
webappFunctionChannel.call("""window.NativeShell.castCallback("$action", $keep, $err, $result);""")
webappFunctionChannel.call(
"""window.NativeShell.castCallback("$action", $keep, $err, $result);""",
)
}
},
)
Expand Down
10 changes: 7 additions & 3 deletions app/src/main/java/org/jellyfin/mobile/player/PlayerViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import org.koin.core.qualifier.named
import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean

@Suppress("TooManyFunctions")
class PlayerViewModel(application: Application) : AndroidViewModel(application), KoinComponent, Player.Listener {
private val apiClient: ApiClient = get()
private val displayPreferencesApi: DisplayPreferencesApi = apiClient.displayPreferencesApi
Expand Down Expand Up @@ -105,7 +106,10 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application),
private val playerEventChannel: Channel<PlayerEvent> by inject(named(PLAYER_EVENT_CHANNEL))

val mediaSession: MediaSession by lazy {
MediaSession(getApplication<Application>().applicationContext, javaClass.simpleName.removePrefix(BuildConfig.APPLICATION_ID)).apply {
MediaSession(
getApplication<Application>().applicationContext,
javaClass.simpleName.removePrefix(BuildConfig.APPLICATION_ID),
).apply {
@Suppress("DEPRECATION")
setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS or MediaSession.FLAG_HANDLES_MEDIA_BUTTONS)
setCallback(mediaSessionCallback)
Expand Down Expand Up @@ -451,9 +455,9 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application),
}
Player.STATE_ENDED -> {
reportPlaybackStop()

if (!mediaQueueManager.next())
if (!mediaQueueManager.next()) {
releasePlayer()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,21 @@ class AudioNotificationManager(

override fun getCurrentLargeIcon(player: Player, callback: PlayerNotificationManager.BitmapCallback): Bitmap? {
val iconUri = controller.metadata.description.iconUri
return if (currentIconUri != iconUri || currentBitmap == null) {
// Cache the bitmap for the current song so that successive calls to
// `getCurrentLargeIcon` don't cause the bitmap to be recreated.
currentIconUri = iconUri
serviceScope.launch {
currentBitmap = iconUri?.let {
resolveUriAsBitmap(it)
return when {
currentIconUri != iconUri || currentBitmap == null -> {
// Cache the bitmap for the current song so that successive calls to
// `getCurrentLargeIcon` don't cause the bitmap to be recreated.
currentIconUri = iconUri
serviceScope.launch {
currentBitmap = iconUri?.let {
resolveUriAsBitmap(it)
}
currentBitmap?.let { callback.onBitmap(it) }
}
currentBitmap?.let { callback.onBitmap(it) }
null
}
null
} else currentBitmap
else -> currentBitmap
}
}

private suspend fun resolveUriAsBitmap(uri: Uri): Bitmap? = withContext(Dispatchers.IO) {
Expand Down
47 changes: 30 additions & 17 deletions app/src/main/java/org/jellyfin/mobile/player/audio/MediaService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ class MediaService : MediaBrowserServiceCompat() {
private fun setPlaybackError() {
val errorState = PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_ERROR, 0, 1f)
.setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_SUPPORTED, getString(R.string.media_service_item_not_found))
.setErrorMessage(
PlaybackStateCompat.ERROR_CODE_NOT_SUPPORTED,
getString(R.string.media_service_item_not_found),
)
.build()
mediaSession.setPlaybackState(errorState)
}
Expand Down Expand Up @@ -305,37 +308,47 @@ class MediaService : MediaBrowserServiceCompat() {
}
if (recents != null) {
preparePlaylist(recents, 0, playWhenReady)
} else setPlaybackError()
} else {
setPlaybackError()
}
}
}

override fun onPrepareFromMediaId(mediaId: String, playWhenReady: Boolean, extras: Bundle?) {
if (mediaId == LibraryPage.RESUME) {
// Requested recents
onPrepare(playWhenReady)
} else serviceScope.launch {
val result = libraryBrowser.buildPlayQueue(mediaId)
if (result != null) {
val (playbackQueue, initialPlaybackIndex) = result
preparePlaylist(playbackQueue, initialPlaybackIndex, playWhenReady)
} else setPlaybackError()
} else {
serviceScope.launch {
val result = libraryBrowser.buildPlayQueue(mediaId)
if (result != null) {
val (playbackQueue, initialPlaybackIndex) = result
preparePlaylist(playbackQueue, initialPlaybackIndex, playWhenReady)
} else {
setPlaybackError()
}
}
}
}

override fun onPrepareFromSearch(query: String, playWhenReady: Boolean, extras: Bundle?) {
if (query.isEmpty()) {
// No search provided, fallback to recents
onPrepare(playWhenReady)
} else serviceScope.launch {
val results = try {
libraryBrowser.getSearchResults(query, extras)
} catch (e: ApiClientException) {
Timber.e(e)
null
} else {
serviceScope.launch {
val results = try {
libraryBrowser.getSearchResults(query, extras)
} catch (e: ApiClientException) {
Timber.e(e)
null
}
if (results != null) {
preparePlaylist(results, 0, playWhenReady)
} else {
setPlaybackError()
}
}
if (results != null) {
preparePlaylist(results, 0, playWhenReady)
} else setPlaybackError()
}
}

Expand Down
Loading