Implemented Shuffle feature #22, removed track cover from table #21, and started created the Settings Activity #14
This commit is contained in:
Generated
+8
@@ -1,5 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.id="Mear" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id="Mear" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="java-gradle" name="Java-Gradle">
|
||||||
|
<configuration>
|
||||||
|
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||||
|
<option name="BUILDABLE" value="false" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
|
|||||||
Generated
BIN
Binary file not shown.
@@ -2,6 +2,8 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.example.mear">
|
package="com.example.mear">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
@@ -9,6 +11,14 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
<activity
|
||||||
|
android:name=".SettingsActivity"
|
||||||
|
android:label="@string/title_activity_settings"
|
||||||
|
android:parentActivityName=".MainActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="com.example.mear.MainActivity"/>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/title_activity_main"
|
android:label="@string/title_activity_main"
|
||||||
@@ -21,6 +31,4 @@
|
|||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.example.mear
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.preference.PreferenceActivity
|
||||||
|
import android.support.annotation.LayoutRes
|
||||||
|
import android.support.v7.app.ActionBar
|
||||||
|
import android.support.v7.app.AppCompatDelegate
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [android.preference.PreferenceActivity] which implements and proxies the necessary calls
|
||||||
|
* to be used with AppCompat.
|
||||||
|
*/
|
||||||
|
abstract class AppCompatPreferenceActivity : PreferenceActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
delegate.installViewFactory()
|
||||||
|
delegate.onCreate(savedInstanceState)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onPostCreate(savedInstanceState)
|
||||||
|
delegate.onPostCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
val supportActionBar: ActionBar?
|
||||||
|
get() = delegate.supportActionBar
|
||||||
|
|
||||||
|
fun setSupportActionBar(toolbar: Toolbar?) {
|
||||||
|
delegate.setSupportActionBar(toolbar)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMenuInflater(): MenuInflater {
|
||||||
|
return delegate.menuInflater
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setContentView(@LayoutRes layoutResID: Int) {
|
||||||
|
delegate.setContentView(layoutResID)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setContentView(view: View) {
|
||||||
|
delegate.setContentView(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setContentView(view: View, params: ViewGroup.LayoutParams) {
|
||||||
|
delegate.setContentView(view, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addContentView(view: View, params: ViewGroup.LayoutParams) {
|
||||||
|
delegate.addContentView(view, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostResume() {
|
||||||
|
super.onPostResume()
|
||||||
|
delegate.onPostResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTitleChanged(title: CharSequence, color: Int) {
|
||||||
|
super.onTitleChanged(title, color)
|
||||||
|
delegate.setTitle(title)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
super.onConfigurationChanged(newConfig)
|
||||||
|
delegate.onConfigurationChanged(newConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
delegate.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
delegate.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidateOptionsMenu() {
|
||||||
|
delegate.invalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val delegate: AppCompatDelegate by lazy {
|
||||||
|
AppCompatDelegate.create(this, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.example.mear
|
package com.example.mear
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.media.MediaPlayer
|
import android.media.MediaPlayer
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
@@ -49,6 +48,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
PreviousTrack.setOnClickListener {
|
PreviousTrack.setOnClickListener {
|
||||||
playPreviousSongTrack()
|
playPreviousSongTrack()
|
||||||
}
|
}
|
||||||
|
ShuffleTracks.setOnClickListener {
|
||||||
|
toggleShuffle()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private fun initializeCompletionListener() {
|
private fun initializeCompletionListener() {
|
||||||
trackPlayer!!.setOnCompletionListener {
|
trackPlayer!!.setOnCompletionListener {
|
||||||
@@ -65,6 +67,26 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun toggleShuffle() {
|
||||||
|
val shuffleText = ShuffleTracks.text.toString()
|
||||||
|
val on = getString(R.string.shuffle_on)
|
||||||
|
val off = getString(R.string.shuffle_off)
|
||||||
|
when (shuffleText) {
|
||||||
|
on -> {
|
||||||
|
shuffleOn = false
|
||||||
|
ShuffleTracks.setText(R.string.shuffle_off)
|
||||||
|
}
|
||||||
|
off -> {
|
||||||
|
shuffleOn = true
|
||||||
|
ShuffleTracks.setText(R.string.shuffle_on)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
shuffleOn = false
|
||||||
|
ShuffleTracks.setText(R.string.shuffle_off)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun playSongTrack() {
|
private fun playSongTrack() {
|
||||||
PlayTrack.isEnabled = true
|
PlayTrack.isEnabled = true
|
||||||
try {
|
try {
|
||||||
@@ -156,8 +178,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
PlayTypes.PlayPreviousSong -> {
|
PlayTypes.PlayPreviousSong -> {
|
||||||
songIndex = songCount
|
songIndex = songCount
|
||||||
if (currentSong!! != 0) {
|
if (currentSong!! != 0) {
|
||||||
|
if (!shuffleOn!!) {
|
||||||
songIndex = currentSong!!.dec()
|
songIndex = currentSong!!.dec()
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
songIndex = Random.nextInt(0, songCount!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PlayTypes.PlaySong -> {
|
PlayTypes.PlaySong -> {
|
||||||
songIndex = Random.nextInt(0, songCount!!)
|
songIndex = Random.nextInt(0, songCount!!)
|
||||||
@@ -165,8 +192,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
PlayTypes.PlayNextSong -> {
|
PlayTypes.PlayNextSong -> {
|
||||||
songIndex = 0
|
songIndex = 0
|
||||||
if (currentSong!! != songCount!!) {
|
if (currentSong!! != songCount!!) {
|
||||||
|
if (!shuffleOn!!) {
|
||||||
songIndex = currentSong!!.inc()
|
songIndex = currentSong!!.inc()
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
songIndex = Random.nextInt(0, songCount!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,6 +236,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private var trackPlayer: MediaPlayer? = null
|
private var trackPlayer: MediaPlayer? = null
|
||||||
private var currentSong: Int? = null
|
private var currentSong: Int? = null
|
||||||
private var playerInitialized: Boolean? = null
|
private var playerInitialized: Boolean? = null
|
||||||
|
private var shuffleOn: Boolean? = null
|
||||||
private var songCount: Int? = null
|
private var songCount: Int? = null
|
||||||
|
|
||||||
private enum class PlayTypes {
|
private enum class PlayTypes {
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
package com.example.mear
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.media.RingtoneManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.preference.ListPreference
|
||||||
|
import android.preference.Preference
|
||||||
|
import android.preference.PreferenceActivity
|
||||||
|
import android.preference.PreferenceFragment
|
||||||
|
import android.preference.PreferenceManager
|
||||||
|
import android.preference.RingtonePreference
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.support.v4.app.NavUtils
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [PreferenceActivity] that presents a set of application settings. On
|
||||||
|
* handset devices, settings are presented as a single list. On tablets,
|
||||||
|
* settings are split by category, with category headers shown to the left of
|
||||||
|
* the list of settings.
|
||||||
|
*
|
||||||
|
* See [Android Design: Settings](http://developer.android.com/design/patterns/settings.html)
|
||||||
|
* for design guidelines and the [Settings API Guide](http://developer.android.com/guide/topics/ui/settings.html)
|
||||||
|
* for more information on developing a Settings UI.
|
||||||
|
*/
|
||||||
|
class SettingsActivity : AppCompatPreferenceActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setupActionBar()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the [android.app.ActionBar], if the API is available.
|
||||||
|
*/
|
||||||
|
private fun setupActionBar() {
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(featureId: Int, item: MenuItem): Boolean {
|
||||||
|
val id = item.itemId
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
if (!super.onMenuItemSelected(featureId, item)) {
|
||||||
|
NavUtils.navigateUpFromSameTask(this)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onMenuItemSelected(featureId, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
override fun onIsMultiPane(): Boolean {
|
||||||
|
return isXLargeTablet(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
override fun onBuildHeaders(target: List<PreferenceActivity.Header>) {
|
||||||
|
loadHeadersFromResource(R.xml.pref_headers, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method stops fragment injection in malicious applications.
|
||||||
|
* Make sure to deny any unknown fragments here.
|
||||||
|
*/
|
||||||
|
override fun isValidFragment(fragmentName: String): Boolean {
|
||||||
|
return PreferenceFragment::class.java.name == fragmentName
|
||||||
|
|| GeneralPreferenceFragment::class.java.name == fragmentName
|
||||||
|
|| DataSyncPreferenceFragment::class.java.name == fragmentName
|
||||||
|
|| NotificationPreferenceFragment::class.java.name == fragmentName
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fragment shows general preferences only. It is used when the
|
||||||
|
* activity is showing a two-pane settings UI.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
class GeneralPreferenceFragment : PreferenceFragment() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
addPreferencesFromResource(R.xml.pref_general)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
|
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
|
||||||
|
// to their values. When their values change, their summaries are
|
||||||
|
// updated to reflect the new value, per the Android Design
|
||||||
|
// guidelines.
|
||||||
|
bindPreferenceSummaryToValue(findPreference("example_text"))
|
||||||
|
bindPreferenceSummaryToValue(findPreference("example_list"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val id = item.itemId
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
startActivity(Intent(activity, SettingsActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fragment shows notification preferences only. It is used when the
|
||||||
|
* activity is showing a two-pane settings UI.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
class NotificationPreferenceFragment : PreferenceFragment() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
addPreferencesFromResource(R.xml.pref_notification)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
|
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
|
||||||
|
// to their values. When their values change, their summaries are
|
||||||
|
// updated to reflect the new value, per the Android Design
|
||||||
|
// guidelines.
|
||||||
|
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val id = item.itemId
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
startActivity(Intent(activity, SettingsActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fragment shows data and sync preferences only. It is used when the
|
||||||
|
* activity is showing a two-pane settings UI.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
class DataSyncPreferenceFragment : PreferenceFragment() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
addPreferencesFromResource(R.xml.pref_data_sync)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
|
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
|
||||||
|
// to their values. When their values change, their summaries are
|
||||||
|
// updated to reflect the new value, per the Android Design
|
||||||
|
// guidelines.
|
||||||
|
bindPreferenceSummaryToValue(findPreference("sync_frequency"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val id = item.itemId
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
startActivity(Intent(activity, SettingsActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A preference value change listener that updates the preference's summary
|
||||||
|
* to reflect its new value.
|
||||||
|
*/
|
||||||
|
private val sBindPreferenceSummaryToValueListener = Preference.OnPreferenceChangeListener { preference, value ->
|
||||||
|
val stringValue = value.toString()
|
||||||
|
|
||||||
|
if (preference is ListPreference) {
|
||||||
|
// For list preferences, look up the correct display value in
|
||||||
|
// the preference's 'entries' list.
|
||||||
|
val listPreference = preference
|
||||||
|
val index = listPreference.findIndexOfValue(stringValue)
|
||||||
|
|
||||||
|
// Set the summary to reflect the new value.
|
||||||
|
preference.setSummary(
|
||||||
|
if (index >= 0)
|
||||||
|
listPreference.entries[index]
|
||||||
|
else
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
} else if (preference is RingtonePreference) {
|
||||||
|
// For ringtone preferences, look up the correct display value
|
||||||
|
// using RingtoneManager.
|
||||||
|
if (TextUtils.isEmpty(stringValue)) {
|
||||||
|
// Empty values correspond to 'silent' (no ringtone).
|
||||||
|
preference.setSummary(R.string.pref_ringtone_silent)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val ringtone = RingtoneManager.getRingtone(
|
||||||
|
preference.getContext(), Uri.parse(stringValue)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (ringtone == null) {
|
||||||
|
// Clear the summary if there was a lookup error.
|
||||||
|
preference.setSummary(null)
|
||||||
|
} else {
|
||||||
|
// Set the summary to reflect the new ringtone display
|
||||||
|
// name.
|
||||||
|
val name = ringtone.getTitle(preference.getContext())
|
||||||
|
preference.setSummary(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// For all other preferences, set the summary to the value's
|
||||||
|
// simple string representation.
|
||||||
|
preference.summary = stringValue
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to determine if the device has an extra-large screen. For
|
||||||
|
* example, 10" tablets are extra-large.
|
||||||
|
*/
|
||||||
|
private fun isXLargeTablet(context: Context): Boolean {
|
||||||
|
return context.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK >= Configuration.SCREENLAYOUT_SIZE_XLARGE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a preference's summary to its value. More specifically, when the
|
||||||
|
* preference's value is changed, its summary (line of text below the
|
||||||
|
* preference title) is updated to reflect the value. The summary is also
|
||||||
|
* immediately updated upon calling this method. The exact display format is
|
||||||
|
* dependent on the type of preference.
|
||||||
|
|
||||||
|
* @see .sBindPreferenceSummaryToValueListener
|
||||||
|
*/
|
||||||
|
private fun bindPreferenceSummaryToValue(preference: Preference) {
|
||||||
|
// Set the listener to watch for value changes.
|
||||||
|
preference.onPreferenceChangeListener = sBindPreferenceSummaryToValueListener
|
||||||
|
|
||||||
|
// Trigger the listener immediately with the preference's
|
||||||
|
// current value.
|
||||||
|
sBindPreferenceSummaryToValueListener.onPreferenceChange(
|
||||||
|
preference,
|
||||||
|
PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(preference.context)
|
||||||
|
.getString(preference.key, "")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,8 +28,7 @@ class DatabaseManager(ctx: Context): ManagedSQLiteOpenHelper(ctx, "Mear",
|
|||||||
"Track", true,
|
"Track", true,
|
||||||
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
|
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
|
||||||
"Title" to TEXT, "Album" to TEXT, "Artist" to TEXT,
|
"Title" to TEXT, "Album" to TEXT, "Artist" to TEXT,
|
||||||
"Cover" to BLOB, "Duration" to INTEGER,
|
"Duration" to INTEGER, "FilePath" to TEXT
|
||||||
"FilePath" to TEXT
|
|
||||||
)
|
)
|
||||||
db!!.createTable(
|
db!!.createTable(
|
||||||
"TrackCount", true,
|
"TrackCount", true,
|
||||||
|
|||||||
@@ -26,20 +26,12 @@ class TrackManager(var allSongPath: MutableList<String>) {
|
|||||||
val trackLenghStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
val trackLenghStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
||||||
trackLength = (trackLenghStr.toInt()/1000)
|
trackLength = (trackLenghStr.toInt()/1000)
|
||||||
|
|
||||||
var art: ByteArray? = null
|
|
||||||
if (mmr.embeddedPicture==null) {
|
|
||||||
art = ByteArray(0)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
art = mmr.embeddedPicture
|
|
||||||
}
|
|
||||||
if (trackTitle == null || trackArtist == null || trackAlbum == null ||
|
if (trackTitle == null || trackArtist == null || trackAlbum == null ||
|
||||||
trackLenghStr == null) {
|
trackLenghStr == null) {
|
||||||
println("dd")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val track = Track(id, trackTitle, trackArtist, trackAlbum, trackLength,
|
val track = Track(id, trackTitle, trackArtist, trackAlbum, trackLength,
|
||||||
art!!, musicPath)
|
ByteArray(0), musicPath)
|
||||||
dumpToDatabase(ctx, track)
|
dumpToDatabase(ctx, track)
|
||||||
id++
|
id++
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ class TrackRepository(val context: Context) {
|
|||||||
val artist = columns.getValue("Artist").toString()
|
val artist = columns.getValue("Artist").toString()
|
||||||
val album = columns.getValue("Album").toString()
|
val album = columns.getValue("Album").toString()
|
||||||
val duration = columns.getValue("Duration").toString().toInt()
|
val duration = columns.getValue("Duration").toString().toInt()
|
||||||
val cover = columns.getValue("Cover").toString().toByteArray()
|
|
||||||
val songPath = columns.getValue("FilePath").toString()
|
val songPath = columns.getValue("FilePath").toString()
|
||||||
|
|
||||||
val track = Track(id.toString().toInt(), title.toString(),artist,album,
|
val track = Track(id.toString().toInt(), title.toString(),artist,album,
|
||||||
duration,cover,songPath)
|
duration, ByteArray(0),songPath)
|
||||||
tracks.add(track)
|
tracks.add(track)
|
||||||
|
|
||||||
return track
|
return track
|
||||||
@@ -41,11 +40,10 @@ class TrackRepository(val context: Context) {
|
|||||||
val artist = columns.getValue("Artist").toString()
|
val artist = columns.getValue("Artist").toString()
|
||||||
var album = columns.getValue("Album").toString()
|
var album = columns.getValue("Album").toString()
|
||||||
val duration = columns.getValue("Duration").toString().toInt()
|
val duration = columns.getValue("Duration").toString().toInt()
|
||||||
var cover = columns.getValue("Cover").toString().toByteArray()
|
|
||||||
var filePath = columns.getValue("FilePath").toString()
|
var filePath = columns.getValue("FilePath").toString()
|
||||||
|
|
||||||
val track = Track(id, title, artist, album, duration,
|
val track = Track(id, title, artist, album, duration,
|
||||||
cover, filePath)
|
ByteArray(0), filePath)
|
||||||
|
|
||||||
return track
|
return track
|
||||||
}
|
}
|
||||||
@@ -68,8 +66,7 @@ class TrackRepository(val context: Context) {
|
|||||||
"Album" to track.album,
|
"Album" to track.album,
|
||||||
"Artist" to track.artist,
|
"Artist" to track.artist,
|
||||||
"Duration" to track.length,
|
"Duration" to track.length,
|
||||||
"FilePath" to track.songPath,
|
"FilePath" to track.songPath)
|
||||||
"Cover" to track.TrackCover)
|
|
||||||
}
|
}
|
||||||
fun createSongCount(songCount: Int) = context.database.use {
|
fun createSongCount(songCount: Int) = context.database.use {
|
||||||
insert("TrackCount",
|
insert("TrackCount",
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M11.5,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zm6.5,-6v-5.5c0,-3.07 -2.13,-5.64 -5,-6.32V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5v0.68c-2.87,0.68 -5,3.25 -5,6.32V16l-2,2v1h17v-1l-2,-2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-.25 1.97,-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01.25,-1.97.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z"/>
|
||||||
|
</vector>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
tools:layout_editor_absoluteX="0dp">
|
tools:layout_editor_absoluteX="0dp">
|
||||||
<ImageView
|
<ImageView
|
||||||
tools:srcCompat="@tools:sample/backgrounds/scenic[2]"
|
tools:srcCompat="@tools:sample/backgrounds/scenic[2]"
|
||||||
android:id="@+id/TrackCover" android:layout_height="326dp"
|
android:id="@+id/TrackCover" android:layout_height="269dp"
|
||||||
android:layout_width="match_parent"/>
|
android:layout_width="match_parent"/>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<Button
|
<Button
|
||||||
android:text="Shuffle"
|
android:text="Shuffle"
|
||||||
android:layout_height="wrap_content" android:id="@+id/ShuffleTracks" android:layout_weight="1"
|
android:layout_height="wrap_content" android:id="@+id/ShuffleTracks" android:layout_weight="1"
|
||||||
android:layout_width="1dp"/>
|
android:layout_width="21dp"/>
|
||||||
<Button
|
<Button
|
||||||
android:text="Repeat"
|
android:text="Repeat"
|
||||||
android:layout_height="wrap_content" android:id="@+id/RepeatList" android:layout_weight="1"
|
android:layout_height="wrap_content" android:id="@+id/RepeatList" android:layout_weight="1"
|
||||||
|
|||||||
@@ -7,4 +7,80 @@
|
|||||||
<string name="nav_header_desc">Navigation header</string>
|
<string name="nav_header_desc">Navigation header</string>
|
||||||
<string name="action_settings">Settings</string>
|
<string name="action_settings">Settings</string>
|
||||||
<string name="title_activity_main">MainActivity</string>
|
<string name="title_activity_main">MainActivity</string>
|
||||||
|
|
||||||
|
<string name="shuffle_on">Shuffle On</string>
|
||||||
|
<string name="shuffle_off">Shuffle Off</string>
|
||||||
|
<string name="title_activity_settings">Settings</string>
|
||||||
|
|
||||||
|
<!-- Strings related to Settings -->
|
||||||
|
|
||||||
|
<!-- Example General settings -->
|
||||||
|
<string name="pref_header_general">General</string>
|
||||||
|
|
||||||
|
<string name="pref_title_social_recommendations">Enable social recommendations</string>
|
||||||
|
<string name="pref_description_social_recommendations">Recommendations for people to contact based on your message
|
||||||
|
history
|
||||||
|
</string>
|
||||||
|
|
||||||
|
<string name="pref_title_display_name">Display name</string>
|
||||||
|
<string name="pref_default_display_name">John Smith</string>
|
||||||
|
|
||||||
|
<string name="pref_title_add_friends_to_messages">Add friends to messages</string>
|
||||||
|
<string-array name="pref_example_list_titles">
|
||||||
|
<item>Always</item>
|
||||||
|
<item>When possible</item>
|
||||||
|
<item>Never</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="pref_example_list_values">
|
||||||
|
<item>1</item>
|
||||||
|
<item>0</item>
|
||||||
|
<item>-1</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Example settings for Data & Sync -->
|
||||||
|
<string name="pref_header_data_sync">Data & sync</string>
|
||||||
|
|
||||||
|
<string name="pref_title_sync_frequency">Sync frequency</string>
|
||||||
|
<string-array name="pref_sync_frequency_titles">
|
||||||
|
<item>15 minutes</item>
|
||||||
|
<item>30 minutes</item>
|
||||||
|
<item>1 hour</item>
|
||||||
|
<item>3 hours</item>
|
||||||
|
<item>6 hours</item>
|
||||||
|
<item>Never</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="pref_sync_frequency_values">
|
||||||
|
<item>15</item>
|
||||||
|
<item>30</item>
|
||||||
|
<item>60</item>
|
||||||
|
<item>180</item>
|
||||||
|
<item>360</item>
|
||||||
|
<item>-1</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="list_preference_entries">
|
||||||
|
<item>Entry 1</item>
|
||||||
|
<item>Entry 2</item>
|
||||||
|
<item>Entry 3</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="list_preference_entry_values">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="multi_select_list_preference_default_value"/>
|
||||||
|
|
||||||
|
<string name="pref_title_system_sync_settings">System sync settings</string>
|
||||||
|
|
||||||
|
<!-- Example settings for Notifications -->
|
||||||
|
<string name="pref_header_notifications">Notifications</string>
|
||||||
|
|
||||||
|
<string name="pref_title_new_message_notifications">New message notifications</string>
|
||||||
|
|
||||||
|
<string name="pref_title_ringtone">Ringtone</string>
|
||||||
|
<string name="pref_ringtone_silent">Silent</string>
|
||||||
|
|
||||||
|
<string name="pref_title_vibrate">Vibrate</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
|
||||||
|
dismiss it. -->
|
||||||
|
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
|
||||||
|
<ListPreference
|
||||||
|
android:key="sync_frequency"
|
||||||
|
android:title="@string/pref_title_sync_frequency"
|
||||||
|
android:entries="@array/pref_sync_frequency_titles"
|
||||||
|
android:entryValues="@array/pref_sync_frequency_values"
|
||||||
|
android:defaultValue="180"
|
||||||
|
android:negativeButtonText="@null"
|
||||||
|
android:positiveButtonText="@null"/>
|
||||||
|
|
||||||
|
<!-- This preference simply launches an intent when selected. Use this UI sparingly, per
|
||||||
|
design guidelines. -->
|
||||||
|
<Preference android:title="@string/pref_title_system_sync_settings">
|
||||||
|
<intent android:action="android.settings.SYNC_SETTINGS"/>
|
||||||
|
</Preference>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="example_switch"
|
||||||
|
android:title="@string/pref_title_social_recommendations"
|
||||||
|
android:summary="@string/pref_description_social_recommendations"
|
||||||
|
android:defaultValue="true"/>
|
||||||
|
|
||||||
|
<!-- NOTE: EditTextPreference accepts EditText attributes. -->
|
||||||
|
<!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="example_text"
|
||||||
|
android:title="@string/pref_title_display_name"
|
||||||
|
android:defaultValue="@string/pref_default_display_name"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:inputType="textCapWords"
|
||||||
|
android:capitalize="words"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:maxLines="1"/>
|
||||||
|
|
||||||
|
<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
|
||||||
|
dismiss it. -->
|
||||||
|
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
|
||||||
|
<ListPreference
|
||||||
|
android:key="example_list"
|
||||||
|
android:title="@string/pref_title_add_friends_to_messages"
|
||||||
|
android:defaultValue="-1"
|
||||||
|
android:entries="@array/pref_example_list_titles"
|
||||||
|
android:entryValues="@array/pref_example_list_values"
|
||||||
|
android:negativeButtonText="@null"
|
||||||
|
android:positiveButtonText="@null"/>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- These settings headers are only used on tablets. -->
|
||||||
|
|
||||||
|
<header
|
||||||
|
android:fragment="com.example.mear.SettingsActivity$GeneralPreferenceFragment"
|
||||||
|
android:title="@string/pref_header_general"
|
||||||
|
android:icon="@drawable/ic_info_black_24dp"/>
|
||||||
|
|
||||||
|
<header
|
||||||
|
android:fragment="com.example.mear.SettingsActivity$NotificationPreferenceFragment"
|
||||||
|
android:title="@string/pref_header_notifications"
|
||||||
|
android:icon="@drawable/ic_notifications_black_24dp"/>
|
||||||
|
|
||||||
|
<header
|
||||||
|
android:fragment="com.example.mear.SettingsActivity$DataSyncPreferenceFragment"
|
||||||
|
android:title="@string/pref_header_data_sync"
|
||||||
|
android:icon="@drawable/ic_sync_black_24dp"/>
|
||||||
|
|
||||||
|
</preference-headers>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- A 'parent' preference, which enables/disables child preferences (below)
|
||||||
|
when checked/unchecked. -->
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="notifications_new_message"
|
||||||
|
android:title="@string/pref_title_new_message_notifications"
|
||||||
|
android:defaultValue="true"/>
|
||||||
|
|
||||||
|
<!-- Allows the user to choose a ringtone in the 'notification' category. -->
|
||||||
|
<!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
|
||||||
|
<!-- NOTE: RingtonePreference's summary should be set to its value by the activity code. -->
|
||||||
|
<RingtonePreference
|
||||||
|
android:dependency="notifications_new_message"
|
||||||
|
android:key="notifications_new_message_ringtone"
|
||||||
|
android:title="@string/pref_title_ringtone"
|
||||||
|
android:ringtoneType="notification"
|
||||||
|
android:defaultValue="content://settings/system/notification_sound"/>
|
||||||
|
|
||||||
|
<!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
|
||||||
|
<SwitchPreference
|
||||||
|
android:dependency="notifications_new_message"
|
||||||
|
android:key="notifications_new_message_vibrate"
|
||||||
|
android:title="@string/pref_title_vibrate"
|
||||||
|
android:defaultValue="true"/>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
Reference in New Issue
Block a user