Add about dialog

Add an about dialog with information about this app.
This commit is contained in:
OxygenCobalt 2020-12-18 10:05:31 -07:00
parent 4933531ca3
commit 0d32ab0f7e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
29 changed files with 463 additions and 37 deletions

0
FAQ.md Normal file
View file

0
LIBRARIES.md Normal file
View file

0
LICENSES.md Normal file
View file

View file

@ -51,13 +51,14 @@ dependencies {
// Kotlin
//noinspection DifferentStdlibGradleVersion
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// --- SUPPORT ---
// General
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.activity:activity-ktx:1.2.0-beta01'
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01'
implementation 'androidx.activity:activity-ktx:1.2.0-beta02'
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta02'
// Layout
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
@ -79,6 +80,9 @@ dependencies {
// Preferences
implementation 'androidx.preference:preference-ktx:1.1.1'
// Opening links
implementation 'androidx.browser:browser:1.3.0'
// --- THIRD PARTY ---
// ExoPlayer

View file

@ -7,6 +7,8 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<queries />
<!-- TODO: Backup -->
<application
android:icon="@mipmap/ic_launcher"

View file

@ -19,6 +19,7 @@ import org.oxycblt.auxio.ui.toColor
// FIXME: Fix bug where fast navigation will break the animations and
// lead to nothing being displayed [Possibly Un-fixable]
// FIXME: Compat issue with Versions 5 that leads to progress bar looking off
// TODO: Try to heavily refactor edge-to-edge
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View file

@ -90,13 +90,8 @@ class CompactPlaybackFragment : Fragment() {
override fun onResume() {
super.onResume()
playbackModel.disableAnimation()
// Use the caveman method of getting a view as storing the binding will cause a memory
// leak.
val playbackControls = binding.playbackControls
val iconPauseToPlay = ContextCompat.getDrawable(
requireContext(), R.drawable.ic_pause_to_play
) as AnimatedVectorDrawable
@ -109,19 +104,19 @@ class CompactPlaybackFragment : Fragment() {
if (playbackModel.canAnimate) {
if (it) {
// Animate the icon transition when the playing status switches
playbackControls?.setImageDrawable(iconPlayToPause)
binding.playbackControls.setImageDrawable(iconPlayToPause)
iconPlayToPause.start()
} else {
playbackControls?.setImageDrawable(iconPauseToPlay)
binding.playbackControls.setImageDrawable(iconPauseToPlay)
iconPauseToPlay.start()
}
} else {
// Use static icons on the first firing of this observer so that the icons
// don't animate on startup, which looks weird.
if (it) {
playbackControls?.setImageResource(R.drawable.ic_pause_large)
binding.playbackControls.setImageResource(R.drawable.ic_pause_large)
} else {
playbackControls?.setImageResource(R.drawable.ic_play_large)
binding.playbackControls.setImageResource(R.drawable.ic_play_large)
}
playbackModel.enableAnimation()

View file

@ -28,7 +28,9 @@ import org.oxycblt.auxio.ui.toColor
*/
class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
private val playbackModel: PlaybackViewModel by activityViewModels()
private val binding: FragmentPlaybackBinding by memberBinding(FragmentPlaybackBinding::inflate)
private val binding: FragmentPlaybackBinding by memberBinding(FragmentPlaybackBinding::inflate) {
binding.playbackSong.isSelected = false
}
override fun onCreateView(
inflater: LayoutInflater,
@ -199,12 +201,6 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
return binding.root
}
override fun onStop() {
super.onStop()
binding.playbackSong.isSelected = false
}
// Seeking callbacks
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {

View file

@ -17,7 +17,8 @@ import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.ui.isInIrregularLandscapeMode
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.isIrregularLandscape
/**
* A [Fragment] that contains both the user queue and the next queue, with the ability to
@ -49,7 +50,8 @@ class QueueFragment : Fragment() {
findNavController().navigateUp()
}
if (!requireActivity().isInIrregularLandscapeMode()) {
if (!requireActivity().isIrregularLandscape() &&
SettingsManager.getInstance().edgeEnabled) {
setOnApplyWindowInsetsListener @Suppress("DEPRECATION") { _, insets ->
val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).top

View file

@ -5,7 +5,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentSettingsBinding
import org.oxycblt.auxio.settings.ui.AboutDialog
class SettingsFragment : Fragment() {
override fun onCreateView(
@ -15,6 +17,13 @@ class SettingsFragment : Fragment() {
): View {
val binding = FragmentSettingsBinding.inflate(inflater)
binding.settingsToolbar.setOnMenuItemClickListener {
if (it.itemId == R.id.action_open_about) {
AboutDialog().show(childFragmentManager, "DIALOG")
true
} else false
}
return binding.root
}
}

View file

@ -17,7 +17,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.settings.adapters.AccentAdapter
import org.oxycblt.auxio.settings.ui.AccentAdapter
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.createToast

View file

@ -0,0 +1,121 @@
package org.oxycblt.auxio.settings.ui
import android.app.Dialog
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentAboutBinding
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.logE
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.createToast
import org.oxycblt.auxio.ui.handleTransparentSystemBars
import org.oxycblt.auxio.ui.handleTransparentSystemNavBar
import org.oxycblt.auxio.ui.isIrregularLandscape
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.toColor
import java.lang.Exception
class AboutDialog : BottomSheetDialogFragment() {
override fun getTheme() = R.style.Theme_BottomSheetFix
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = FragmentAboutBinding.inflate(layoutInflater)
val musicStore = MusicStore.getInstance()
val settingsManager = SettingsManager.getInstance()
// --- UI SETUP ---
// Apply edge-to-edge to the dialog if supported/enabled.
if (settingsManager.edgeEnabled && !requireActivity().isIrregularLandscape()) {
requireDialog().window?.apply {
navigationBarColor = R.color.background.toColor(requireContext())
handleTransparentSystemNavBar(resources.configuration)
}
}
binding.aboutVersion.text = BuildConfig.VERSION_NAME
binding.aboutCode.setOnClickListener { openLinkInBrowser(LINK_CODEBASE) }
binding.aboutFaq.setOnClickListener { openLinkInBrowser(LINK_FAQ) }
binding.aboutLicenses.setOnClickListener { openLinkInBrowser(LINK_LICENSES) }
binding.aboutSongCount.text = getString(
R.string.format_songs_loaded, musicStore.songs.size.toString()
)
binding.aboutAuthor.text = getString(
R.string.format_author, getString(R.string.author_oxycblt)
)
logD("Dialog created.")
return binding.root
}
private fun openLinkInBrowser(link: String) {
check(link in LINKS) { "Invalid link." }
try {
val tabsIntent = CustomTabsIntent.Builder()
.setShareState(CustomTabsIntent.SHARE_STATE_ON)
.setShowTitle(true)
.build()
val uri = link.toUri()
val manager = requireActivity().packageManager
val browserCandidates = manager.queryIntentActivities(tabsIntent.intent, 0)
// If there are candidates for this link, then launch it through that.
if (browserCandidates.size > 0) {
tabsIntent.launchUrl(requireActivity(), uri)
} else {
// If there are no candidates, then fallback to another list of browsers
val browserIntent = Intent(Intent.ACTION_VIEW, uri)
browserIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val fallbackCandidates = manager.queryIntentActivities(browserIntent, 0)
// If there are candidates here, then launch those.
if (fallbackCandidates.size > 0) {
requireActivity().startActivity(browserIntent)
} else {
// Otherwise they don't have a browser on their phone, meaning they should
// just see an error.
getString(R.string.error_no_browser).createToast(requireContext())
}
}
} catch (e: Exception) {
logE("Browser intent launching failed [Probably android's fault]")
e.printStackTrace()
// Sometimes people have """""Browsers""""" on their phone according to android,
// but they actually don't so here's a fallback for that.
getString(R.string.error_no_browser).createToast(requireContext())
}
}
companion object {
// TODO: Change dev to master
private const val LINK_CODEBASE = "https://github.com/oxygencobalt/Auxio"
private const val LINK_FAQ = "$LINK_CODEBASE/blob/master/FAQ.md"
private const val LINK_LICENSES = "$LINK_CODEBASE/blob/master/LICENSES.md"
val LINKS = arrayOf(LINK_CODEBASE, LINK_FAQ, LINK_LICENSES)
}
}

View file

@ -1,4 +1,4 @@
package org.oxycblt.auxio.settings.adapters
package org.oxycblt.auxio.settings.ui
import android.content.res.ColorStateList
import android.view.LayoutInflater

View file

@ -22,9 +22,8 @@ import org.oxycblt.auxio.settings.SettingsManager
* TODO: Make edge-to-edge work in irregular mode
* @return True if we are in the irregular landscape mode, false if not.
*/
fun Activity.isInIrregularLandscapeMode(): Boolean {
return SettingsManager.getInstance().edgeEnabled &&
isLandscape(resources) &&
fun Activity.isIrregularLandscape(): Boolean {
return isLandscape(resources) &&
!isSystemBarOnBottom(this)
}
@ -93,3 +92,31 @@ fun Window.handleTransparentSystemBars(config: Configuration) {
}
}
}
/**
* Handle only the transparent navigation bar.
*/
fun Window.handleTransparentSystemNavBar(config: Configuration) {
fun isNight() = config.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insetsController?.let { controller ->
val appearance = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
val mask = if (isNight()) 0 else appearance
controller.setSystemBarsAppearance(appearance, mask)
}
} else {
val flags = decorView.systemUiVisibility
decorView.systemUiVisibility =
if (isNight()) {
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() and
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
} else {
flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR or
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
}
}

View file

@ -16,20 +16,21 @@ import kotlin.reflect.KProperty
/**
* A delegate that creates a binding that can be used as a member variable without nullability or
* memory leaks.
* @param bindingFactory The ViewBinding inflation method that should be used
* @param onDestroy Any code that should be run when the binding is destroyed.
*/
fun <T : ViewBinding> Fragment.memberBinding(
viewBindingFactory: (LayoutInflater) -> T,
disposeEvents: T.() -> Unit = {}
) = FragmentBinderDelegate(this, viewBindingFactory, disposeEvents)
bindingFactory: (LayoutInflater) -> T, onDestroy: T.() -> Unit = {}
) = FragmentBinderDelegate(this, bindingFactory, onDestroy)
/**
* The delegate for the [binder] shortcut function.
* The delegate for the [memberBinding] shortcut function.
* Adapted from KAHelpers (https://github.com/FunkyMuse/KAHelpers/tree/master/viewbinding)
*/
class FragmentBinderDelegate<T : ViewBinding>(
private val fragment: Fragment,
private val binder: (LayoutInflater) -> T,
private val disposeEvents: T.() -> Unit
private val inflate: (LayoutInflater) -> T,
private val onDestroy: T.() -> Unit
) : ReadOnlyProperty<Fragment, T>, LifecycleObserver {
private var fragmentBinding: T? = null
@ -46,8 +47,8 @@ class FragmentBinderDelegate<T : ViewBinding>(
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
viewLifecycleOwnerLiveData.observe(this@observeOwnerThroughCreation) { owner ->
owner.viewOwner()
viewLifecycleOwnerLiveData.observe(this@observeOwnerThroughCreation) {
it.viewOwner()
}
}
})
@ -69,13 +70,13 @@ class FragmentBinderDelegate<T : ViewBinding>(
throw IllegalStateException("Fragment views are destroyed.")
}
return binder(LayoutInflater.from(thisRef.requireContext())).also { fragmentBinding = it }
return inflate(LayoutInflater.from(thisRef.requireContext())).also { fragmentBinding = it }
}
@Suppress("UNUSED")
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun dispose() {
fragmentBinding?.disposeEvents()
fragmentBinding?.onDestroy()
fragmentBinding = null
}
}

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
</vector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM21.41,6.34l-3.75,-3.75 -2.53,2.54 3.75,3.75 2.53,-2.54z"/>
</vector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z"/>
</vector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M4,6L2,6v16h16v-2L4,20L4,6zM22,2L6,2v16h16L22,2zM19,11L9,11L9,9h10v2zM15,15L9,15v-2h6v2zM19,7L9,7L9,5h10v2z"/>
</vector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M4.01,2L4,22h16V8l-6,-6H4.01zM13,9V3.5L18.5,9H13z"/>
</vector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>

View file

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:theme="@style/Theme.Neutral">
<ImageView
android:id="@+id/about_auxio_icon"
android:layout_width="@dimen/size_app_icon"
android:layout_height="@dimen/size_app_icon"
android:layout_marginTop="@dimen/margin_medium"
android:contentDescription="@string/description_auxio_icon"
android:src="@mipmap/ic_launcher"
app:layout_constraintEnd_toStartOf="@+id/about_app_name"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/about_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_medium"
android:fontFamily="@font/inter_semibold"
android:text="@string/app_name"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
app:layout_constraintBottom_toBottomOf="@+id/about_auxio_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/about_auxio_icon"
app:layout_constraintTop_toTopOf="@+id/about_auxio_icon" />
<TextView
android:id="@+id/about_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_small"
android:text="@string/app_desc"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/about_auxio_icon" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/version_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="@dimen/padding_medium"
app:layout_constraintBottom_toTopOf="@+id/about_code"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/about_desc"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_chainStyle="packed">
<ImageView
android:id="@+id/about_version_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/label_version"
android:src="@drawable/ic_version"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/about_version_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_medium"
android:text="@string/label_version"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
app:layout_constraintBottom_toTopOf="@+id/about_version"
app:layout_constraintStart_toEndOf="@+id/about_version_icon"
app:layout_constraintTop_toTopOf="@+id/about_version_icon" />
<TextView
android:id="@+id/about_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
app:layout_constraintBottom_toBottomOf="@+id/about_version_icon"
app:layout_constraintStart_toEndOf="@+id/about_version_icon"
app:layout_constraintTop_toBottomOf="@+id/about_version_title"
tools:text="0.0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/about_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ui_ripple"
android:clickable="true"
android:drawablePadding="@dimen/padding_medium"
android:focusable="true"
android:padding="@dimen/padding_medium"
android:text="@string/label_code"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
app:drawableLeftCompat="@drawable/ic_code"
app:layout_constraintBottom_toTopOf="@+id/about_faq"
app:layout_constraintTop_toBottomOf="@+id/version_container" />
<TextView
android:id="@+id/about_licenses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ui_ripple"
android:clickable="true"
android:drawablePadding="@dimen/padding_medium"
android:focusable="true"
android:padding="@dimen/padding_medium"
android:text="@string/label_licenses"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
app:drawableLeftCompat="@drawable/ic_license"
app:layout_constraintBottom_toTopOf="@+id/about_song_count"
app:layout_constraintTop_toBottomOf="@+id/about_faq" />
<TextView
android:id="@+id/about_faq"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ui_ripple"
android:clickable="true"
android:drawablePadding="@dimen/padding_medium"
android:focusable="true"
android:padding="@dimen/padding_medium"
android:text="@string/label_faq"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
app:drawableLeftCompat="@drawable/ic_about"
app:layout_constraintBottom_toTopOf="@+id/about_licenses"
app:layout_constraintTop_toBottomOf="@+id/about_code"
tools:layout_editor_absoluteX="0dp" />
<TextView
android:id="@+id/about_song_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/padding_medium"
android:padding="@dimen/padding_medium"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
app:drawableLeftCompat="@drawable/ic_song"
app:layout_constraintBottom_toTopOf="@+id/about_author"
app:layout_constraintTop_toBottomOf="@+id/about_licenses"
tools:text="Songs Loaded: 1616" />
<TextView
android:id="@+id/about_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/padding_medium"
android:padding="@dimen/padding_medium"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
app:drawableLeftCompat="@drawable/ic_author"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/about_song_count"
tools:text="Created by OxygenCobalt" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -8,10 +8,11 @@
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/song_toolbar"
android:id="@+id/settings_toolbar"
style="@style/Toolbar.Style"
android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal"
app:menu="@menu/menu_settings"
app:title="@string/setting_title" />
<androidx.fragment.app.FragmentContainerView

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_open_about"
android:title="@string/label_about"
android:icon="@drawable/ic_about"
app:showAsAction="always" />
</menu>

View file

@ -34,6 +34,8 @@
<dimen name="size_play_pause">70dp</dimen>
<dimen name="size_play_pause_compact">36dp</dimen>
<dimen name="size_app_icon">60dp</dimen>
<!-- Text Size Namespace | Text Sizes -->
<dimen name="text_size_min">10sp</dimen>
<dimen name="text_size_increment">2sp</dimen>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="author_oxycblt">OxygenCobalt</string>
</resources>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Auxio</string>
<string name="app_desc">A sensible and customizable music player for android.</string>
<!-- Label Namespace | Static Labels -->
<string name="label_retry">Retry</string>
@ -36,6 +37,12 @@
<string name="label_channel">Music Playback</string>
<string name="label_service_playback">The music playback service for Auxio.</string>
<string name="label_about">About</string>
<string name="label_version">Version</string>
<string name="label_code">View on Github</string>
<string name="label_licenses">Licenses</string>
<string name="label_faq">FAQ</string>
<!-- Settings namespace | Settings-related labels -->
<string name="setting_title">Settings</string>
<string name="setting_ui">Appearance</string>
@ -94,6 +101,7 @@
<string name="error_no_music">No music found.</string>
<string name="error_music_load_failed">Music loading failed.</string>
<string name="error_no_perms">Permissions to read storage are needed.</string>
<string name="error_no_browser">Could not open link.</string>
<!-- Hint Namespace | EditText Hints -->
<string name="hint_search_library">Search Library…</string>
@ -116,6 +124,8 @@
<string name="description_shuffle_on">Turn shuffle on</string>
<string name="description_shuffle_off">Turn shuffle off</string>
<string name="description_change_loop">Change Repeat Mode</string>
<string name="description_auxio_icon">Auxio icon</string>
<string name="description_code">Code</string>
<!-- Placeholder Namespace | Placeholder values -->
<string name="placeholder_genre">Unknown Genre</string>
@ -151,6 +161,8 @@
<string name="format_double_counts">%1$s, %2$s</string>
<string name="format_next_from">Next From: %s</string>
<string name="format_accent_summary">&lt;b>%1$s&lt;/b>:&#160;%2$s</string>
<string name="format_songs_loaded">Songs Loaded: %s</string>
<string name="format_author">Created by %s</string>
<plurals name="format_song_count">
<item quantity="one">%s Song</item>

View file

@ -167,4 +167,10 @@
<item name="android:paddingEnd">@dimen/padding_medium</item>
<item name="android:background">@drawable/ui_small_unbounded_ripple</item>
</style>
<!-- Bottomsheet style -->
<style name="Theme.BottomSheetFix" parent="@style/Theme.Design.BottomSheetDialog">
<item name="android:windowIsFloating">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>

View file

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.4.20"
ext.kotlin_version = "1.4.21"
repositories {
google()