diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index 0ae0cb25..5639d78a 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -77,6 +77,8 @@ android { ignore 'MissingTranslation', 'UnusedQuantity', 'MissingQuantity' warning 'ImpliedQuantity' disable 'ObsoleteLintCustomCheck' + textReport true + checkDependencies true } namespace 'org.moire.ultrasonic' diff --git a/ultrasonic/lint-baseline.xml b/ultrasonic/lint-baseline.xml index f3794053..bb988f23 100644 --- a/ultrasonic/lint-baseline.xml +++ b/ultrasonic/lint-baseline.xml @@ -1,5 +1,5 @@ - + @@ -55,7 +55,7 @@ errorLine2=" ~~~~~~~~"> @@ -103,50 +103,6 @@ column="9"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -117,43 +117,7 @@ - - - - - - - - - - - - - - - - - - - - - + android:resource="@xml/appwidget_info"/> diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index 23b00828..6206816e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -13,6 +13,7 @@ import android.content.Intent import android.content.res.ColorStateList import android.content.res.Resources import android.media.AudioManager +import android.os.Build import android.os.Bundle import android.provider.MediaStore import android.provider.SearchRecentSuggestions @@ -246,14 +247,19 @@ class NavigationActivity : AppCompatActivity() { } private fun updateNavigationHeaderForServer() { + // Only show the vector graphic on Android 11 or earlier + val showVectorBackground = (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) + val activeServer = activeServerProvider.getActiveServer() if (cachedServerCount == 0) selectServerButton?.text = getString(R.string.main_setup_server, activeServer.name) else selectServerButton?.text = activeServer.name - val foregroundColor = ServerColor.getForegroundColor(this, activeServer.color) - val backgroundColor = ServerColor.getBackgroundColor(this, activeServer.color) + val foregroundColor = + ServerColor.getForegroundColor(this, activeServer.color, showVectorBackground) + val backgroundColor = + ServerColor.getBackgroundColor(this, activeServer.color) if (activeServer.index == 0) selectServerButton?.icon = @@ -265,6 +271,11 @@ class NavigationActivity : AppCompatActivity() { selectServerButton?.iconTint = ColorStateList.valueOf(foregroundColor) selectServerButton?.setTextColor(foregroundColor) headerBackgroundImage?.setBackgroundColor(backgroundColor) + + // Hide the vector graphic on Android 12 or later + if (!showVectorBackground) { + headerBackgroundImage?.setImageDrawable(null) + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt index a182166e..bca305aa 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt @@ -1,7 +1,6 @@ package org.moire.ultrasonic.adapters import android.annotation.SuppressLint -import android.content.Context import android.view.LayoutInflater import android.view.MenuItem import android.view.MotionEvent @@ -21,7 +20,6 @@ class TrackViewBinder( val onContextMenuClick: ((MenuItem, Track) -> Boolean)? = null, val checkable: Boolean, val draggable: Boolean, - context: Context, val lifecycleOwner: LifecycleOwner, val createContextMenu: (View, Track) -> PopupMenu = { view, _ -> Utils.createPopupMenu( @@ -36,8 +34,6 @@ class TrackViewBinder( // Set our layout files val layout = R.layout.list_item_track - private val imageHelper: Utils.ImageHelper = Utils.ImageHelper(context) - override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): TrackViewHolder { return TrackViewHolder(inflater.inflate(layout, parent, false)) } @@ -56,8 +52,6 @@ class TrackViewBinder( } } - holder.imageHelper = imageHelper - // Remove observer before binding holder.observableChecked.removeObservers(lifecycleOwner) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt index 140848e8..9d69167b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt @@ -1,12 +1,12 @@ package org.moire.ultrasonic.adapters -import android.graphics.drawable.Drawable import android.view.View import android.widget.Checkable import android.widget.CheckedTextView import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView +import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.lifecycle.MutableLiveData import androidx.recyclerview.widget.RecyclerView @@ -38,7 +38,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable var check: CheckedTextView = view.findViewById(R.id.song_check) var drag: ImageView = view.findViewById(R.id.song_drag) var observableChecked = MutableLiveData(false) - lateinit var imageHelper: Utils.ImageHelper private var rating: LinearLayout = view.findViewById(R.id.song_five_star) private var fiveStar1: ImageView = view.findViewById(R.id.song_five_star_1) @@ -125,11 +124,15 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable rxBusSubscription?.dispose() } + private val playingIcon by lazy { + ContextCompat.getDrawable(view.context, R.drawable.ic_stat_play)!! + } + private fun setPlayIcon(isPlaying: Boolean) { if (isPlaying && !isPlayingCached) { isPlayingCached = true title.setCompoundDrawablesWithIntrinsicBounds( - imageHelper.playingImage, null, null, null + playingIcon, null, null, null ) } else if (!isPlaying && isPlayingCached) { isPlayingCached = false @@ -214,13 +217,13 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable when (status) { DownloadState.DONE -> { - showStatusImage(imageHelper.downloadedImage) + showStatusImage(R.drawable.ic_downloaded) } DownloadState.PINNED -> { - showStatusImage(imageHelper.pinImage) + showStatusImage(R.drawable.ic_menu_pin) } DownloadState.FAILED -> { - showStatusImage(imageHelper.errorImage) + showStatusImage(R.drawable.ic_baseline_error) } DownloadState.DOWNLOADING -> { showProgress() @@ -237,10 +240,14 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable } } - private fun showStatusImage(image: Drawable?) { + private fun showStatusImage(image: Int?) { progressIndicator.isVisible = false statusImage.isVisible = true - statusImage.setImageDrawable(image) + if (image != null) { + statusImage.setImageResource(image) + } else { + statusImage.setImageDrawable(null) + } } private fun showIndefiniteProgress() { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/Utils.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/Utils.kt index 6fb37037..f7eeb386 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/Utils.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/Utils.kt @@ -1,15 +1,11 @@ package org.moire.ultrasonic.adapters -import android.content.Context -import android.graphics.drawable.Drawable import android.view.MenuInflater import android.view.View import android.widget.PopupMenu -import androidx.core.content.ContextCompat import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.domain.Identifiable -import org.moire.ultrasonic.util.Settings object Utils { @JvmStatic @@ -31,41 +27,6 @@ object Utils { return popup } - /** - * Provides cached drawables for the UI - */ - class ImageHelper(context: Context) { - - lateinit var errorImage: Drawable - lateinit var pinImage: Drawable - lateinit var downloadedImage: Drawable - lateinit var downloadingImage: List - lateinit var playingImage: Drawable - var theme: String - - init { - theme = Settings.theme - getDrawables(context) - } - - private fun getDrawables(context: Context) { - pinImage = ContextCompat.getDrawable(context, R.drawable.ic_menu_pin)!! - downloadedImage = - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_0)!! - errorImage = ContextCompat.getDrawable(context, R.drawable.ic_baseline_error)!! - downloadingImage = listOf( - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_1)!!, - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_2)!!, - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_3)!!, - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_4)!!, - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_5)!!, - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_6)!!, - ContextCompat.getDrawable(context, R.drawable.stat_sys_download_anim_7)!!, - ) - playingImage = ContextCompat.getDrawable(context, R.drawable.ic_stat_play)!! - } - } - interface SectionedBinder { fun getSectionName(item: Identifiable): String } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/DownloadsFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/DownloadsFragment.kt index e8b453d0..2f7a0832 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/DownloadsFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/DownloadsFragment.kt @@ -57,7 +57,6 @@ class DownloadsFragment : MultiListFragment() { { _, _ -> true }, checkable = false, draggable = false, - context = requireContext(), lifecycleOwner = viewLifecycleOwner ) ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index 55cdce69..8b253627 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -69,7 +69,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { private var userNameEditText: TextInputLayout? = null private var passwordEditText: TextInputLayout? = null private var selfSignedSwitch: SwitchMaterial? = null - private var ldapSwitch: SwitchMaterial? = null + private var plaintextSwitch: SwitchMaterial? = null private var jukeboxSwitch: SwitchMaterial? = null private var saveButton: Button? = null private var testButton: Button? = null @@ -102,7 +102,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { userNameEditText = view.findViewById(R.id.edit_server_username) passwordEditText = view.findViewById(R.id.edit_server_password) selfSignedSwitch = view.findViewById(R.id.edit_self_signed) - ldapSwitch = view.findViewById(R.id.edit_ldap) + plaintextSwitch = view.findViewById(R.id.edit_plaintext) jukeboxSwitch = view.findViewById(R.id.edit_jukebox) saveButton = view.findViewById(R.id.edit_save) testButton = view.findViewById(R.id.edit_test) @@ -195,7 +195,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { private fun updateColor(color: Int?) { val image = ContextCompat.getDrawable(requireContext(), R.drawable.thumb_drawable) - currentColor = ServerColor.getBackgroundColor(requireContext(), color) + currentColor = color ?: ServerColor.getBackgroundColor(requireContext(), null) image?.setTint(currentColor) serverColorImageView?.background = image } @@ -221,7 +221,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { ::selfSignedSwitch.name, selfSignedSwitch!!.isChecked ) savedInstanceState.putBoolean( - ::ldapSwitch.name, ldapSwitch!!.isChecked + ::plaintextSwitch.name, plaintextSwitch!!.isChecked ) savedInstanceState.putBoolean( ::jukeboxSwitch.name, jukeboxSwitch!!.isChecked @@ -258,7 +258,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { savedInstanceState.getString(::passwordEditText.name) ) selfSignedSwitch!!.isChecked = savedInstanceState.getBoolean(::selfSignedSwitch.name) - ldapSwitch!!.isChecked = savedInstanceState.getBoolean(::ldapSwitch.name) + plaintextSwitch!!.isChecked = savedInstanceState.getBoolean(::plaintextSwitch.name) jukeboxSwitch!!.isChecked = savedInstanceState.getBoolean(::jukeboxSwitch.name) updateColor(savedInstanceState.getInt(::serverColorImageView.name)) if (savedInstanceState.containsKey(::selectedColor.name)) @@ -277,7 +277,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { userNameEditText!!.editText?.setText(currentServerSetting!!.userName) passwordEditText!!.editText?.setText(currentServerSetting!!.password) selfSignedSwitch!!.isChecked = currentServerSetting!!.allowSelfSignedCertificate - ldapSwitch!!.isChecked = currentServerSetting!!.forcePlainTextPassword + plaintextSwitch!!.isChecked = currentServerSetting!!.forcePlainTextPassword jukeboxSwitch!!.isChecked = currentServerSetting!!.jukeboxByDefault updateColor(currentServerSetting!!.color) } @@ -331,7 +331,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { currentServerSetting!!.userName = userNameEditText!!.editText?.text.toString() currentServerSetting!!.password = passwordEditText!!.editText?.text.toString() currentServerSetting!!.allowSelfSignedCertificate = selfSignedSwitch!!.isChecked - currentServerSetting!!.forcePlainTextPassword = ldapSwitch!!.isChecked + currentServerSetting!!.forcePlainTextPassword = plaintextSwitch!!.isChecked currentServerSetting!!.jukeboxByDefault = jukeboxSwitch!!.isChecked } @@ -354,7 +354,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { currentServerSetting!!.userName != userNameEditText!!.editText?.text.toString() || currentServerSetting!!.password != passwordEditText!!.editText?.text.toString() || currentServerSetting!!.allowSelfSignedCertificate != selfSignedSwitch!!.isChecked || - currentServerSetting!!.forcePlainTextPassword != ldapSwitch!!.isChecked || + currentServerSetting!!.forcePlainTextPassword != plaintextSwitch!!.isChecked || currentServerSetting!!.jukeboxByDefault != jukeboxSwitch!!.isChecked } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/NowPlayingFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/NowPlayingFragment.kt index 04c03efe..87c63d62 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/NowPlayingFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/NowPlayingFragment.kt @@ -86,9 +86,9 @@ class NowPlayingFragment : Fragment() { private fun update() { try { if (mediaPlayerController.isPlaying) { - playButton!!.setIconResource(R.drawable.media_pause_normal) + playButton!!.setIconResource(R.drawable.media_pause) } else { - playButton!!.setIconResource(R.drawable.media_start_normal) + playButton!!.setIconResource(R.drawable.media_start) } val file = mediaPlayerController.currentMediaItem?.toTrack() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt index e3309031..6881fe95 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt @@ -838,13 +838,11 @@ class PlayerFragment : viewAdapter.register( TrackViewBinder( onItemClick = clickHandler, + onContextMenuClick = { menu, id -> onContextMenuItemSelected(menu, id) }, checkable = false, draggable = true, - context = requireContext(), lifecycleOwner = viewLifecycleOwner, - createContextMenu = { view, track -> onCreateContextMenu(view, track) }, - onContextMenuClick = { menu, id -> onContextMenuItemSelected(menu, id) }, - ).apply { + ) { view, track -> onCreateContextMenu(view, track) }.apply { this.startDrag = { holder -> dragTouchHelper.startDrag(holder) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SearchFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SearchFragment.kt index cfb8d0d8..e90e06b5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SearchFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SearchFragment.kt @@ -120,7 +120,6 @@ class SearchFragment : MultiListFragment(), KoinComponent { onContextMenuClick = ::onContextMenuItemSelected, checkable = false, draggable = false, - context = requireContext(), lifecycleOwner = viewLifecycleOwner ) ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSelectorFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSelectorFragment.kt index 9db2cb6b..bb5a9227 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSelectorFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSelectorFragment.kt @@ -63,7 +63,6 @@ class ServerSelectorFragment : Fragment() { listView?.adapter = serverRowAdapter listView?.onItemClickListener = AdapterView.OnItemClickListener { parent, _, position, _ -> - val server = parent.getItemAtPosition(position) as ServerSetting ActiveServerProvider.setActiveServerById(server.id) findNavController().popBackStack(R.id.mainFragment, false) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt index a2188078..2f16475c 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt @@ -133,7 +133,6 @@ open class TrackCollectionFragment : MultiListFragment() { onContextMenuClick = { menu, id -> onContextMenuItemSelected(menu, id) }, checkable = true, draggable = false, - context = requireContext(), lifecycleOwner = viewLifecycleOwner ) ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt index 59be1edc..40908d1b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt @@ -16,7 +16,6 @@ import java.io.InputStream import java.io.OutputStream import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CountDownLatch -import org.moire.ultrasonic.BuildConfig import org.moire.ultrasonic.R import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient import org.moire.ultrasonic.api.subsonic.throwOnFailure @@ -46,7 +45,7 @@ class ImageLoader( .addRequestHandler(AvatarRequestHandler(apiClient)) .memoryCache(LruCache(calculateMemoryCacheSize(context))) .build().apply { - setIndicatorsEnabled(BuildConfig.DEBUG) + // setIndicatorsEnabled(BuildConfig.DEBUG) } private fun load(request: ImageRequest) = when (request) { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt index d2c861c4..fd8943e3 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt @@ -1203,7 +1203,7 @@ class AutoMediaBrowserCallback(var player: Player, val libraryService: MediaLibr mediaId, null, false, - icon = R.drawable.media_start_normal + icon = R.drawable.media_start ) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt index 7f3c8145..ad9ceacd 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt @@ -30,6 +30,8 @@ import org.moire.ultrasonic.activity.NavigationActivity import org.moire.ultrasonic.app.UApp import org.moire.ultrasonic.audiofx.EqualizerController import org.moire.ultrasonic.data.ActiveServerProvider +import org.moire.ultrasonic.domain.Track +import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider import org.moire.ultrasonic.service.DownloadService import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService import org.moire.ultrasonic.service.RxBus @@ -172,6 +174,12 @@ class PlaybackService : MediaLibraryService(), KoinComponent { } override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) { + updateWidgetTrack(mediaItem?.toTrack()) + cacheNextSongs() + } + + override fun onIsPlayingChanged(isPlaying: Boolean) { + updateWidgetPlayerState(isPlaying) cacheNextSongs() } } @@ -205,4 +213,14 @@ class PlaybackService : MediaLibraryService(), KoinComponent { .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) .build() } + + private fun updateWidgetTrack(song: Track?) { + val context = UApp.applicationContext() + UltrasonicAppWidgetProvider.notifyTrackChange(context, song) + } + + private fun updateWidgetPlayerState(isPlaying: Boolean) { + val context = UApp.applicationContext() + UltrasonicAppWidgetProvider.notifyPlayerStateChange(context, isPlaying) + } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt index ffd579cc..337f91f0 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt @@ -14,10 +14,12 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Build +import android.os.Bundle import android.os.Environment import android.view.KeyEvent +import android.view.View.GONE +import android.view.View.VISIBLE import android.widget.RemoteViews -import java.lang.Exception import org.moire.ultrasonic.R import org.moire.ultrasonic.activity.NavigationActivity import org.moire.ultrasonic.domain.Track @@ -27,141 +29,197 @@ import org.moire.ultrasonic.util.Constants import timber.log.Timber /** - * Widget Provider for the Ultrasonic Widgets + * Widget Provider for the Ultrasonic Widget */ @Suppress("MagicNumber") open class UltrasonicAppWidgetProvider : AppWidgetProvider() { - @JvmField - protected var layoutId = 0 + override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { - defaultAppWidget(context, appWidgetIds) + updateTrackAndState(context, appWidgetIds) } - /** - * Initialize given widgets to default state, where we launch Ultrasonic on default click - * and hide actions if service not running. - */ - private fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { - val res = context.resources - val views = RemoteViews(context.packageName, layoutId) - views.setTextViewText(R.id.title, null) - views.setTextViewText(R.id.album, null) - views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)) - linkButtons(context, views, false) - pushUpdate(context, appWidgetIds, views) - } - - private fun pushUpdate(context: Context, appWidgetIds: IntArray?, views: RemoteViews) { - // Update specific list of appWidgetIds if given, otherwise default to all - val manager = AppWidgetManager.getInstance(context) - if (manager != null) { - if (appWidgetIds != null) { - manager.updateAppWidget(appWidgetIds, views) - } else { - manager.updateAppWidget(ComponentName(context, this.javaClass), views) - } - } - } - - /** - * Handle a change notification coming over from [MediaPlayerController] - */ - fun notifyChange(context: Context, currentSong: Track?, playing: Boolean, setAlbum: Boolean) { - if (hasInstances(context)) { - performUpdate(context, currentSong, playing, setAlbum) - } - } - - /** - * Check against [AppWidgetManager] if there are any instances of this widget. - */ - private fun hasInstances(context: Context): Boolean { - val manager = AppWidgetManager.getInstance(context) - if (manager != null) { - val appWidgetIds = manager.getAppWidgetIds(ComponentName(context, javaClass)) - return appWidgetIds.isNotEmpty() - } - return false - } - - /** - * Update all active widget instances by pushing changes - */ - private fun performUpdate( - context: Context, - currentSong: Track?, - playing: Boolean, - setAlbum: Boolean + override fun onAppWidgetOptionsChanged( + context: Context?, + appWidgetManager: AppWidgetManager?, + appWidgetId: Int, + newOptions: Bundle? ) { - Timber.d("Updating Widget") - val res = context.resources - val views = RemoteViews(context.packageName, layoutId) - val title = currentSong?.title - val artist = currentSong?.artist - val album = currentSong?.album - var errorState: CharSequence? = null - - // Show error message? - val status = Environment.getExternalStorageState() - if (status == Environment.MEDIA_SHARED || status == Environment.MEDIA_UNMOUNTED) { - errorState = res.getText(R.string.widget_sdcard_busy) - } else if (status == Environment.MEDIA_REMOVED) { - errorState = res.getText(R.string.widget_sdcard_missing) - } else if (currentSong == null) { - errorState = res.getText(R.string.widget_initial_text) - } - if (errorState != null) { - // Show error state to user - views.setTextViewText(R.id.title, null) - views.setTextViewText(R.id.artist, errorState) - if (setAlbum) { - views.setTextViewText(R.id.album, null) - } - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) - } else { - // No error, so show normal titles - views.setTextViewText(R.id.title, title) - views.setTextViewText(R.id.artist, artist) - if (setAlbum) { - views.setTextViewText(R.id.album, album) - } - } - - // Set correct drawable for pause state - if (playing) { - views.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal) - } else { - views.setImageViewResource(R.id.control_play, R.drawable.media_start_normal) - } - - // Set the cover art - try { - val bitmap = - if (currentSong == null) null else BitmapUtils.getAlbumArtBitmapFromDisk( - currentSong, - 240 - ) - if (bitmap == null) { - // Set default cover art - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) - } else { - views.setImageViewBitmap(R.id.appwidget_coverart, bitmap) - } - } catch (all: Exception) { - Timber.e(all, "Failed to load cover art") - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) - } - - // Link actions buttons to intents - linkButtons(context, views, currentSong != null) - pushUpdate(context, null, views) + updateTrackAndState(context!!, intArrayOf(appWidgetId)) } companion object { + + private var isPlaying: Boolean = false + private var track: Track? = null + + /** + * Pushes the current track details to the widgets + */ + fun notifyTrackChange(context: Context, currentSong: Track?) { + this.track = currentSong + if (hasInstances(context)) { + // The widget won't update correctly if only the track or the state is updated + updateTrackAndState(context, null) + } + } + + /** + * Pushes the current player state to the widgets + */ + fun notifyPlayerStateChange(context: Context, isPlaying: Boolean) { + this.isPlaying = isPlaying + if (hasInstances(context)) { + // The widget won't update correctly if only the track or the state is updated + updateTrackAndState(context, null) + } + } + + /** + * Send the track and the player state to the widgets + */ + private fun updateTrackAndState(context: Context, appWidgetIds: IntArray? = null) { + pushUpdate(context, appWidgetIds) { + updateTrack(context, it, track) + updatePlayerState(it, isPlaying) + } + } + + /** + * Iterates through the instances of the widget, and pushes the update to them + */ + private fun pushUpdate( + context: Context, + appWidgetIds: IntArray? = null, + update: (RemoteViews) -> Unit + ) { + val manager = AppWidgetManager.getInstance(context) + if (manager != null) { + val widgetIds = + appWidgetIds ?: manager.getAppWidgetIds( + ComponentName( + context, + UltrasonicAppWidgetProvider::class.java + ) + ) + + widgetIds.forEach { + val widgetOptions = manager.getAppWidgetOptions(it) + val minHeight = + widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) + val minWidth = + widgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) + val layoutId = getLayout(minHeight, minWidth) + val views = RemoteViews(context.packageName, layoutId) + update(views) + manager.updateAppWidget(it, views) + } + } + } + + /** + * Computes the layout to be displayed for the widget height + */ + private fun getLayout(height: Int, width: Int): Int { + val portrait = (width / height.toFloat()) < 1.8F + if (portrait) return R.layout.appwidget_portrait + if (height > 100) return R.layout.appwidget_landscape + return R.layout.appwidget_landscape_small + } + + /** + * Check against [AppWidgetManager] if there are any instances of this widget. + */ + private fun hasInstances(context: Context): Boolean { + val manager = AppWidgetManager.getInstance(context) + if (manager != null) { + val appWidgetIds = manager.getAppWidgetIds( + ComponentName( + context, + UltrasonicAppWidgetProvider::class.java + ) + ) + return appWidgetIds.isNotEmpty() + } + return false + } + + /** + * Update Player state in widgets + */ + private fun updatePlayerState(views: RemoteViews, isPlaying: Boolean) { + if (isPlaying) { + views.setImageViewResource(R.id.control_play, R.drawable.media_pause) + } else { + views.setImageViewResource(R.id.control_play, R.drawable.media_start) + } + } + + /** + * Update Track details in widgets + */ + private fun updateTrack( + context: Context, + views: RemoteViews, + currentSong: Track? + ) { + Timber.d("Updating Widget") + val res = context.resources + val title = currentSong?.title + val artist = currentSong?.artist + val album = currentSong?.album + var errorState: CharSequence? = null + + // Show error message? + val status = Environment.getExternalStorageState() + if (status == Environment.MEDIA_SHARED || status == Environment.MEDIA_UNMOUNTED) { + errorState = res.getText(R.string.widget_sdcard_busy) + } else if (status == Environment.MEDIA_REMOVED) { + errorState = res.getText(R.string.widget_sdcard_missing) + } else if (currentSong == null) { + errorState = res.getText(R.string.widget_initial_text) + } + if (errorState != null) { + // Show error state to user + views.setViewVisibility(R.id.title, GONE) + views.setViewVisibility(R.id.album, GONE) + views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)) + views.setBoolean(R.id.artist, "setSingleLine", false) + views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) + } else { + // No error, so show normal titles + views.setTextViewText(R.id.title, title) + views.setTextViewText(R.id.artist, artist) + views.setTextViewText(R.id.album, album) + views.setBoolean(R.id.artist, "setSingleLine", true) + views.setViewVisibility(R.id.title, VISIBLE) + views.setViewVisibility(R.id.album, VISIBLE) + } + // Set the cover art + try { + val bitmap = + if (currentSong == null) null else BitmapUtils.getAlbumArtBitmapFromDisk( + currentSong, + 240 + ) + if (bitmap == null) { + // Set default cover art + views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) + } else { + views.setImageViewBitmap(R.id.appwidget_coverart, bitmap) + } + } catch (all: Exception) { + Timber.e(all, "Failed to load cover art") + views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) + } + + // Link actions buttons to intents + linkButtons(context, views, currentSong != null) + } + /** * Link up various button actions using [PendingIntent]. */ diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt deleted file mode 100644 index 5efd3ca8..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * UltrasonicAppWidgetProvider4X1.kt - * Copyright (C) 2009-2022 Ultrasonic developers - * - * Distributed under terms of the GNU GPLv3 license. - */ - -package org.moire.ultrasonic.provider - -import org.moire.ultrasonic.R - -class UltrasonicAppWidgetProvider4X1 : UltrasonicAppWidgetProvider() { - companion object { - @get:Synchronized - var instance: UltrasonicAppWidgetProvider4X1? = null - get() { - if (field == null) { - field = UltrasonicAppWidgetProvider4X1() - } - return field - } - private set - } - - init { - layoutId = R.layout.appwidget4x1 - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt deleted file mode 100644 index 7235a998..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * UltrasonicAppWidgetProvider4X2.kt - * Copyright (C) 2009-2022 Ultrasonic developers - * - * Distributed under terms of the GNU GPLv3 license. - */ - -package org.moire.ultrasonic.provider - -import org.moire.ultrasonic.R - -class UltrasonicAppWidgetProvider4X2 : UltrasonicAppWidgetProvider() { - companion object { - @get:Synchronized - var instance: UltrasonicAppWidgetProvider4X2? = null - get() { - if (field == null) { - field = UltrasonicAppWidgetProvider4X2() - } - return field - } - private set - } - - init { - layoutId = R.layout.appwidget4x2 - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt deleted file mode 100644 index 7b9187cf..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * UltrasonicAppWidgetProvider4X3.kt - * Copyright (C) 2009-2022 Ultrasonic developers - * - * Distributed under terms of the GNU GPLv3 license. - */ - -package org.moire.ultrasonic.provider - -import org.moire.ultrasonic.R - -class UltrasonicAppWidgetProvider4X3 : UltrasonicAppWidgetProvider() { - companion object { - @get:Synchronized - var instance: UltrasonicAppWidgetProvider4X3? = null - get() { - if (field == null) { - field = UltrasonicAppWidgetProvider4X3() - } - return field - } - private set - } - - init { - layoutId = R.layout.appwidget4x3 - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt deleted file mode 100644 index d641ff4a..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * UltrasonicAppWidgetProvider4X4.kt - * Copyright (C) 2009-2022 Ultrasonic developers - * - * Distributed under terms of the GNU GPLv3 license. - */ - -package org.moire.ultrasonic.provider - -import org.moire.ultrasonic.R - -class UltrasonicAppWidgetProvider4X4 : UltrasonicAppWidgetProvider() { - companion object { - @get:Synchronized - var instance: UltrasonicAppWidgetProvider4X4? = null - get() { - if (field == null) { - field = UltrasonicAppWidgetProvider4X4() - } - return field - } - private set - } - - init { - layoutId = R.layout.appwidget4x4 - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt index 64aee927..29208e5b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt @@ -36,10 +36,6 @@ import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider.Companion.OFFLINE_DB_ID import org.moire.ultrasonic.domain.Track import org.moire.ultrasonic.playback.PlaybackService -import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X1 -import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X2 -import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3 -import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4 import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService import org.moire.ultrasonic.util.MainThreadExecutor import org.moire.ultrasonic.util.Settings @@ -201,11 +197,6 @@ class MediaPlayerController( } } - rxBusSubscription += RxBus.stopServiceCommandObservable.subscribe { - // Clear the widget when we stop the service - updateWidget(null) - } - rxBusSubscription += RxBus.shutdownCommandObservable.subscribe { playbackStateSerializer.serializeNow( playlist.map { it.toTrack() }, @@ -236,9 +227,6 @@ class MediaPlayerController( scrobbler.scrobble(currentPlaying, true) } } - - // Update widget - updateWidget(currentPlaying) } private fun clearBookmark() { @@ -267,15 +255,6 @@ class MediaPlayerController( Timber.i("New PlaybackState: %s", newState) } - private fun updateWidget(song: Track?) { - val context = UApp.applicationContext() - - UltrasonicAppWidgetProvider4X1.instance?.notifyChange(context, song, isPlaying, false) - UltrasonicAppWidgetProvider4X2.instance?.notifyChange(context, song, isPlaying, true) - UltrasonicAppWidgetProvider4X3.instance?.notifyChange(context, song, isPlaying, true) - UltrasonicAppWidgetProvider4X4.instance?.notifyChange(context, song, isPlaying, true) - } - fun onDestroy() { if (!created) return diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/ServerColor.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/ServerColor.kt index 565e3aa7..7d4d35d7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/ServerColor.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/ServerColor.kt @@ -8,29 +8,45 @@ package org.moire.ultrasonic.util import android.content.Context +import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils -import org.moire.ultrasonic.R +import com.google.android.material.color.MaterialColors private const val LUMINANCE_LIMIT = 0.5 +private const val LUMINANCE_CORRECTION = -0.25 /** * Contains functions for computing server display colors */ object ServerColor { + + @ColorInt fun getBackgroundColor(context: Context, serverColor: Int?): Int { - return serverColor ?: ContextCompat.getColor( - context, Util.getResourceFromAttribute(context, R.attr.colorPrimary) - ) + return if (serverColor != null) { + MaterialColors.harmonizeWithPrimary(context, serverColor) + } else { + MaterialColors.getColor(context, android.R.attr.colorPrimary, "") + } } - fun getForegroundColor(context: Context, serverColor: Int?): Int { + @ColorInt + fun getForegroundColor( + context: Context, + serverColor: Int?, + showVectorBackground: Boolean = false + ): Int { val backgroundColor = getBackgroundColor(context, serverColor) - val luminance = ColorUtils.calculateLuminance(backgroundColor) + var luminance = ColorUtils.calculateLuminance(backgroundColor) + + // The actual luminance is a good bit lower + // when the background color is being overlayed by the vector + if (showVectorBackground) luminance += LUMINANCE_CORRECTION + return if (luminance < LUMINANCE_LIMIT) { - ContextCompat.getColor(context, R.color.selected_menu_dark) + ContextCompat.getColor(context, org.moire.ultrasonic.R.color.selected_menu_dark) } else { - ContextCompat.getColor(context, R.color.selected_menu_light) + ContextCompat.getColor(context, org.moire.ultrasonic.R.color.selected_menu_light) } } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt index bce819ad..a1c81eb7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt @@ -22,7 +22,7 @@ object Settings { @JvmStatic var theme by StringSetting( getKey(R.string.setting_key_theme), - getKey(R.string.setting_key_theme_dark) + getKey(R.string.setting_key_theme_day_night) ) @JvmStatic diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt index eeada628..4a043715 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt @@ -31,7 +31,6 @@ import android.os.Build import android.os.Environment import android.text.TextUtils import android.util.DisplayMetrics -import android.util.TypedValue import android.view.Gravity import android.view.inputmethod.InputMethodManager import android.widget.Toast @@ -94,21 +93,13 @@ object Util { fun applyTheme(context: Context?) { if (context == null) return val style = getStyleFromSettings(context) + // First set the theme (light, dark, etc.) context.setTheme(style) + // Then set an overlay controlling the status bar behaviour etc. + context.setTheme(R.style.UltrasonicTheme_Base) } private fun getStyleFromSettings(context: Context): Int { - // Migration - // TODO: Remove in June 2023 - when (Settings.theme.lowercase()) { - "fullscreen" -> { - Settings.theme = context.getString(R.string.setting_key_theme_dark) - } - "fullscreenlight" -> { - Settings.theme = context.getString(R.string.setting_key_theme_light) - } - } - return when (Settings.theme.lowercase()) { context.getString(R.string.setting_key_theme_dark) -> { R.style.UltrasonicTheme_Dark @@ -120,7 +111,7 @@ object Util { R.style.UltrasonicTheme_Light } else -> { - R.style.UltrasonicTheme_Dark + R.style.UltrasonicTheme_DayNight } } } @@ -571,13 +562,6 @@ object Util { ) } - fun getResourceFromAttribute(context: Context, resId: Int): Int { - val typedValue = TypedValue() - val theme = context.theme - theme.resolveAttribute(resId, typedValue, true) - return typedValue.resourceId - } - fun isFirstRun(): Boolean { if (Settings.firstRunExecuted) return false diff --git a/ultrasonic/src/main/res/drawable-hdpi/appwidget_dark_bg_trans.9.png b/ultrasonic/src/main/res/drawable-hdpi/appwidget_dark_bg_trans.9.png deleted file mode 100644 index f4fcb51b..00000000 Binary files a/ultrasonic/src/main/res/drawable-hdpi/appwidget_dark_bg_trans.9.png and /dev/null differ diff --git a/ultrasonic/src/main/res/drawable-nodpi/preview4x1.png b/ultrasonic/src/main/res/drawable-nodpi/preview4x1.png deleted file mode 100644 index 2eae0f1a..00000000 Binary files a/ultrasonic/src/main/res/drawable-nodpi/preview4x1.png and /dev/null differ diff --git a/ultrasonic/src/main/res/drawable-nodpi/preview4x2.png b/ultrasonic/src/main/res/drawable-nodpi/preview4x2.png deleted file mode 100644 index ff1e414f..00000000 Binary files a/ultrasonic/src/main/res/drawable-nodpi/preview4x2.png and /dev/null differ diff --git a/ultrasonic/src/main/res/drawable-nodpi/preview4x3.png b/ultrasonic/src/main/res/drawable-nodpi/preview4x3.png deleted file mode 100644 index 665aa40c..00000000 Binary files a/ultrasonic/src/main/res/drawable-nodpi/preview4x3.png and /dev/null differ diff --git a/ultrasonic/src/main/res/drawable/app_widget_background.xml b/ultrasonic/src/main/res/drawable/app_widget_background.xml new file mode 100644 index 00000000..d1807771 --- /dev/null +++ b/ultrasonic/src/main/res/drawable/app_widget_background.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ultrasonic/src/main/res/drawable/circle.xml b/ultrasonic/src/main/res/drawable/circle.xml index bda25c31..23c1d9cd 100644 --- a/ultrasonic/src/main/res/drawable/circle.xml +++ b/ultrasonic/src/main/res/drawable/circle.xml @@ -1,7 +1,7 @@ - + diff --git a/ultrasonic/src/main/res/drawable/default_ripple.xml b/ultrasonic/src/main/res/drawable/default_ripple.xml index 4390ea04..cd11a5d8 100644 --- a/ultrasonic/src/main/res/drawable/default_ripple.xml +++ b/ultrasonic/src/main/res/drawable/default_ripple.xml @@ -5,7 +5,7 @@ - + diff --git a/ultrasonic/src/main/res/drawable/ic_contact_picture.xml b/ultrasonic/src/main/res/drawable/ic_contact_picture.xml index ab3465e4..904f6690 100644 --- a/ultrasonic/src/main/res/drawable/ic_contact_picture.xml +++ b/ultrasonic/src/main/res/drawable/ic_contact_picture.xml @@ -2,8 +2,13 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> + android:viewportHeight="24" + android:tint="?attr/colorControlHighlight"> + + diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_0.xml b/ultrasonic/src/main/res/drawable/ic_downloaded.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/stat_sys_download_anim_0.xml rename to ultrasonic/src/main/res/drawable/ic_downloaded.xml diff --git a/ultrasonic/src/main/res/drawable/media_backward_normal.xml b/ultrasonic/src/main/res/drawable/media_backward.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/media_backward_normal.xml rename to ultrasonic/src/main/res/drawable/media_backward.xml diff --git a/ultrasonic/src/main/res/drawable/media_forward_normal.xml b/ultrasonic/src/main/res/drawable/media_forward.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/media_forward_normal.xml rename to ultrasonic/src/main/res/drawable/media_forward.xml diff --git a/ultrasonic/src/main/res/drawable/media_pause_normal.xml b/ultrasonic/src/main/res/drawable/media_pause.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/media_pause_normal.xml rename to ultrasonic/src/main/res/drawable/media_pause.xml diff --git a/ultrasonic/src/main/res/drawable/media_shuffle_normal.xml b/ultrasonic/src/main/res/drawable/media_shuffle.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/media_shuffle_normal.xml rename to ultrasonic/src/main/res/drawable/media_shuffle.xml diff --git a/ultrasonic/src/main/res/drawable/media_start_normal.xml b/ultrasonic/src/main/res/drawable/media_start.xml similarity index 90% rename from ultrasonic/src/main/res/drawable/media_start_normal.xml rename to ultrasonic/src/main/res/drawable/media_start.xml index 04b5b2bd..cc4ff3f6 100644 --- a/ultrasonic/src/main/res/drawable/media_start_normal.xml +++ b/ultrasonic/src/main/res/drawable/media_start.xml @@ -5,6 +5,6 @@ android:viewportHeight="24" android:tint="?attr/colorControlNormal"> diff --git a/ultrasonic/src/main/res/drawable/media_stop_normal.xml b/ultrasonic/src/main/res/drawable/media_stop.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/media_stop_normal.xml rename to ultrasonic/src/main/res/drawable/media_stop.xml diff --git a/ultrasonic/src/main/res/drawable/media_toggle_list_normal.xml b/ultrasonic/src/main/res/drawable/media_toggle_list.xml similarity index 100% rename from ultrasonic/src/main/res/drawable/media_toggle_list_normal.xml rename to ultrasonic/src/main/res/drawable/media_toggle_list.xml diff --git a/ultrasonic/src/main/res/drawable/rounded_border.xml b/ultrasonic/src/main/res/drawable/rounded_border.xml index 5c60efee..2f2a9842 100644 --- a/ultrasonic/src/main/res/drawable/rounded_border.xml +++ b/ultrasonic/src/main/res/drawable/rounded_border.xml @@ -3,10 +3,10 @@ android:shape="rectangle"> + android:topLeftRadius="28dp" + android:topRightRadius="28dp" + android:bottomRightRadius="28dp" + android:bottomLeftRadius="28dp" /> - + \ No newline at end of file diff --git a/ultrasonic/src/main/res/drawable/select_ripple.xml b/ultrasonic/src/main/res/drawable/select_ripple.xml index f2b692e8..ce8c6310 100644 --- a/ultrasonic/src/main/res/drawable/select_ripple.xml +++ b/ultrasonic/src/main/res/drawable/select_ripple.xml @@ -1,17 +1,16 @@ - - + - + \ No newline at end of file diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_1.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_1.xml deleted file mode 100644 index 34504676..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_1.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_2.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_2.xml deleted file mode 100644 index 7c3b29d9..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_2.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_3.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_3.xml deleted file mode 100644 index 2d55a557..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_3.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_4.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_4.xml deleted file mode 100644 index 8ab08780..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_4.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_5.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_5.xml deleted file mode 100644 index da7a3cce..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_5.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_6.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_6.xml deleted file mode 100644 index ce14d3c4..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_6.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_7.xml b/ultrasonic/src/main/res/drawable/stat_sys_download_anim_7.xml deleted file mode 100644 index 9255455d..00000000 --- a/ultrasonic/src/main/res/drawable/stat_sys_download_anim_7.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/ultrasonic/src/main/res/drawable/widget_preview.xml b/ultrasonic/src/main/res/drawable/widget_preview.xml new file mode 100644 index 00000000..16635c3f --- /dev/null +++ b/ultrasonic/src/main/res/drawable/widget_preview.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/ultrasonic/src/main/res/layout/album_buttons.xml b/ultrasonic/src/main/res/layout/album_buttons.xml index 87bb262a..391f946c 100644 --- a/ultrasonic/src/main/res/layout/album_buttons.xml +++ b/ultrasonic/src/main/res/layout/album_buttons.xml @@ -29,7 +29,7 @@ android:layout_weight="1" android:visibility="gone" android:contentDescription="@string/common.play_now" - app:icon="@drawable/media_start_normal" + app:icon="@drawable/media_start" app:iconGravity="textTop" app:iconSize="26dp" /> @@ -120,7 +120,7 @@ android:layout_weight="1" android:visibility="gone" android:contentDescription="@string/search.more" - app:icon="@drawable/media_forward_normal" + app:icon="@drawable/media_forward" app:iconGravity="textTop" app:iconSize="26dp" /> diff --git a/ultrasonic/src/main/res/layout/appwidget4x1.xml b/ultrasonic/src/main/res/layout/appwidget4x1.xml deleted file mode 100644 index 2c51a624..00000000 --- a/ultrasonic/src/main/res/layout/appwidget4x1.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/appwidget4x3.xml b/ultrasonic/src/main/res/layout/appwidget4x3.xml deleted file mode 100644 index c752f346..00000000 --- a/ultrasonic/src/main/res/layout/appwidget4x3.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/appwidget4x4.xml b/ultrasonic/src/main/res/layout/appwidget4x4.xml deleted file mode 100644 index d4fa7a40..00000000 --- a/ultrasonic/src/main/res/layout/appwidget4x4.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/appwidget4x2.xml b/ultrasonic/src/main/res/layout/appwidget_landscape.xml similarity index 54% rename from ultrasonic/src/main/res/layout/appwidget4x2.xml rename to ultrasonic/src/main/res/layout/appwidget_landscape.xml index fc59026c..cdc82fcc 100644 --- a/ultrasonic/src/main/res/layout/appwidget4x2.xml +++ b/ultrasonic/src/main/res/layout/appwidget_landscape.xml @@ -1,26 +1,35 @@ + a:orientation="horizontal" + a:theme="@style/Theme.AppWidget.AppWidgetContainerCropped" + tools:ignore="UseAppTint"> + a:layout_gravity="center_vertical" + a:layout_marginHorizontal="5dp" + a:gravity="center" + a:orientation="vertical"> + a:gravity="center" + a:orientation="vertical"> + a:paddingEnd="4dip" + a:textAppearance="@style/TextAppearance.Material3.TitleMedium" + tools:text="Title" /> - - + + - + a:textAppearance="@style/TextAppearance.Material3.BodyLarge" + tools:text="Album" /> + + a:orientation="horizontal" + a:paddingTop="4dip" + a:paddingBottom="4dip"> + a:layout_width="0dp" + a:layout_height="40dp" + a:layout_gravity="center" + a:layout_weight="0.6" + a:importantForAccessibility="no" + a:src="@drawable/media_backward" + /> + a:importantForAccessibility="no" + a:src="@drawable/media_start" + /> + a:layout_width="0dp" + a:layout_height="40dp" + a:layout_gravity="center" + a:layout_weight="0.6" + a:importantForAccessibility="no" + a:src="@drawable/media_forward" + /> diff --git a/ultrasonic/src/main/res/layout/appwidget_landscape_small.xml b/ultrasonic/src/main/res/layout/appwidget_landscape_small.xml new file mode 100644 index 00000000..8fc7f14e --- /dev/null +++ b/ultrasonic/src/main/res/layout/appwidget_landscape_small.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/appwidget_portrait.xml b/ultrasonic/src/main/res/layout/appwidget_portrait.xml new file mode 100644 index 00000000..b2cea920 --- /dev/null +++ b/ultrasonic/src/main/res/layout/appwidget_portrait.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/list_header_album.xml b/ultrasonic/src/main/res/layout/list_header_album.xml index c33df633..256082f0 100644 --- a/ultrasonic/src/main/res/layout/list_header_album.xml +++ b/ultrasonic/src/main/res/layout/list_header_album.xml @@ -1,7 +1,7 @@ + a:layout_width="fill_parent" + a:layout_height="wrap_content"> + a:src="@drawable/unknown_album" /> + a:textAppearance="?android:attr/textAppearanceMedium" /> + a:textAppearance="?android:attr/textAppearanceSmall" /> + a:textAppearance="?android:attr/textAppearanceSmall" /> + a:textAppearance="?android:attr/textAppearanceSmall" /> + a:textAppearance="?android:attr/textAppearanceSmall" /> + a:textAppearance="?android:attr/textAppearanceSmall" /> \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/list_item_divider.xml b/ultrasonic/src/main/res/layout/list_item_divider.xml index 1f71852c..289c9ec4 100644 --- a/ultrasonic/src/main/res/layout/list_item_divider.xml +++ b/ultrasonic/src/main/res/layout/list_item_divider.xml @@ -11,9 +11,6 @@ a:layout_height="wrap_content" a:gravity="center_vertical" a:paddingStart="6dp" - a:textAllCaps="true" - a:textAppearance="?android:attr/textAppearanceSmall" - a:textColor="?attr/colorPrimary" - a:textStyle="bold" /> + a:theme="@style/Ultrasonic.AllCapsLabel" /> diff --git a/ultrasonic/src/main/res/layout/list_item_track.xml b/ultrasonic/src/main/res/layout/list_item_track.xml index ad096bdd..55ebfb86 100644 --- a/ultrasonic/src/main/res/layout/list_item_track.xml +++ b/ultrasonic/src/main/res/layout/list_item_track.xml @@ -98,12 +98,12 @@ a:layout_marginTop="8dp" a:layout_marginEnd="10dip" a:indeterminate="true" - app:indicatorColor="?attr/color_menu_selected" + app:indicatorColor="?attr/colorOnSurface" app:indicatorSize="20dp" app:layout_constraintBottom_toTopOf="@id/song_duration" app:layout_constraintEnd_toEndOf="@id/star_barrier" app:layout_constraintTop_toTopOf="parent" - app:trackColor="?attr/color_selected" /> + app:trackColor="?attr/colorSurfaceVariant" /> + /> + android:theme="@style/Ultrasonic.AllCapsLabel" /> + android:text="@string/main.albums_title" /> + android:theme="@style/Ultrasonic.AllCapsLabel" /> @@ -48,7 +48,7 @@ a:scaleType="fitCenter" tools:visibility="gone" a:contentDescription="@string/buttons.play" - app:icon="@drawable/media_start_normal" + app:icon="@drawable/media_start" app:iconGravity="textTop" app:iconSize="48dp" /> @@ -62,7 +62,7 @@ a:contentDescription="@string/buttons.pause" a:focusable="true" a:scaleType="fitCenter" - app:icon="@drawable/media_pause_normal" + app:icon="@drawable/media_pause" app:iconGravity="textTop" app:iconSize="48dp" /> @@ -77,7 +77,7 @@ a:scaleType="fitCenter" tools:visibility="gone" a:contentDescription="@string/buttons.stop" - app:icon="@drawable/media_stop_normal" + app:icon="@drawable/media_stop" app:iconGravity="textTop" app:iconSize="48dp" /> @@ -92,7 +92,7 @@ a:contentDescription="@string/buttons.next" a:focusable="true" a:scaleType="fitCenter" - app:icon="@drawable/media_forward_normal" + app:icon="@drawable/media_forward" app:iconGravity="textTop" app:iconSize="32dp" /> diff --git a/ultrasonic/src/main/res/layout/navigation_activity.xml b/ultrasonic/src/main/res/layout/navigation_activity.xml index a2f722e4..b9c38450 100644 --- a/ultrasonic/src/main/res/layout/navigation_activity.xml +++ b/ultrasonic/src/main/res/layout/navigation_activity.xml @@ -6,7 +6,8 @@ a:id="@+id/drawer_layout" a:layout_width="match_parent" a:layout_height="match_parent" - tools:context="org.moire.ultrasonic.activity.NavigationActivity"> + tools:context="org.moire.ultrasonic.activity.NavigationActivity" + a:fitsSystemWindows="true"> \ No newline at end of file diff --git a/ultrasonic/src/main/res/layout/navigation_header.xml b/ultrasonic/src/main/res/layout/navigation_header.xml index 11ec6a96..2f8abec8 100644 --- a/ultrasonic/src/main/res/layout/navigation_header.xml +++ b/ultrasonic/src/main/res/layout/navigation_header.xml @@ -24,19 +24,20 @@ style="@style/Widget.Material3.Button.TextButton.Icon" a:layout_width="match_parent" a:layout_height="wrap_content" - a:layout_marginTop="0dp" + a:layout_marginStart="3dp" + a:layout_marginTop="24dp" a:background="@drawable/default_ripple" a:gravity="center_vertical" a:paddingHorizontal="22dp" a:paddingTop="16dp" a:paddingBottom="16dp" a:text="@string/main.offline" - a:textAppearance="@style/MenuDrawer.Widget" + a:textAppearance="@style/TextAppearance.Material3.TitleMedium" a:textColor="?attr/colorOnPrimary" - a:textSize="17sp" - a:textStyle="bold" + a:textSize="18sp" app:icon="@drawable/ic_menu_select_server" app:iconPadding="12dp" + app:iconSize="24dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/ultrasonic/src/main/res/layout/now_playing.xml b/ultrasonic/src/main/res/layout/now_playing.xml index 639a14fd..0e671c40 100644 --- a/ultrasonic/src/main/res/layout/now_playing.xml +++ b/ultrasonic/src/main/res/layout/now_playing.xml @@ -6,16 +6,17 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="?attr/colorSecondaryContainer" - tools:ignore="overdraw"> + tools:ignore="Overdraw"> + android:id="@+id/now_playing_image" + android:layout_width="72.0dip" + android:layout_height="72.0dip" + android:layout_marginStart="0dp" + android:elevation="4dp" + android:focusable="true" + android:gravity="center" + android:importantForAccessibility="no" /> diff --git a/ultrasonic/src/main/res/layout/server_edit.xml b/ultrasonic/src/main/res/layout/server_edit.xml index e025c7ff..3c53d649 100644 --- a/ultrasonic/src/main/res/layout/server_edit.xml +++ b/ultrasonic/src/main/res/layout/server_edit.xml @@ -4,238 +4,252 @@ xmlns:tools="http://schemas.android.com/tools" a:layout_width="match_parent" a:layout_height="match_parent" - a:fillViewport="true"> + a:fillViewport="true" + tools:ignore="HardcodedText"> - - - + a:paddingStart="16dp" + a:paddingEnd="16dp"> - + a:hint="@string/settings.server_name" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + - + - + a:layout_marginBottom="20dp" + a:hint="@string/settings.server_address" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/edit_server_name"> - + - + - - + - - - + a:hint="@string/settings.server_username" + app:layout_constraintBottom_toTopOf="@id/edit_server_password" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/edit_authentication_header"> - + - + - + a:layout_marginBottom="21dp" + a:hint="@string/settings.server_password" + app:endIconMode="password_toggle" + app:layout_constraintBottom_toTopOf="@id/edit_advanced_header" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/edit_server_username"> - + - - - - - - - - - - - - - - - - -