Implemented Shuffle feature #22, removed track cover from table #21, and started created the Settings Activity #14
This commit is contained in:
@@ -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
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.media.MediaPlayer
|
||||
import android.media.MediaMetadataRetriever
|
||||
@@ -49,6 +48,9 @@ class MainActivity : AppCompatActivity() {
|
||||
PreviousTrack.setOnClickListener {
|
||||
playPreviousSongTrack()
|
||||
}
|
||||
ShuffleTracks.setOnClickListener {
|
||||
toggleShuffle()
|
||||
}
|
||||
}
|
||||
private fun initializeCompletionListener() {
|
||||
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() {
|
||||
PlayTrack.isEnabled = true
|
||||
try {
|
||||
@@ -156,7 +178,12 @@ class MainActivity : AppCompatActivity() {
|
||||
PlayTypes.PlayPreviousSong -> {
|
||||
songIndex = songCount
|
||||
if (currentSong!! != 0) {
|
||||
songIndex = currentSong!!.dec()
|
||||
if (!shuffleOn!!) {
|
||||
songIndex = currentSong!!.dec()
|
||||
}
|
||||
else {
|
||||
songIndex = Random.nextInt(0, songCount!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
PlayTypes.PlaySong -> {
|
||||
@@ -165,7 +192,12 @@ class MainActivity : AppCompatActivity() {
|
||||
PlayTypes.PlayNextSong -> {
|
||||
songIndex = 0
|
||||
if (currentSong!! != songCount!!) {
|
||||
songIndex = currentSong!!.inc()
|
||||
if (!shuffleOn!!) {
|
||||
songIndex = currentSong!!.inc()
|
||||
}
|
||||
else {
|
||||
songIndex = Random.nextInt(0, songCount!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,6 +236,7 @@ class MainActivity : AppCompatActivity() {
|
||||
private var trackPlayer: MediaPlayer? = null
|
||||
private var currentSong: Int? = null
|
||||
private var playerInitialized: Boolean? = null
|
||||
private var shuffleOn: Boolean? = null
|
||||
private var songCount: Int? = null
|
||||
|
||||
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,
|
||||
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
|
||||
"Title" to TEXT, "Album" to TEXT, "Artist" to TEXT,
|
||||
"Cover" to BLOB, "Duration" to INTEGER,
|
||||
"FilePath" to TEXT
|
||||
"Duration" to INTEGER, "FilePath" to TEXT
|
||||
)
|
||||
db!!.createTable(
|
||||
"TrackCount", true,
|
||||
|
||||
@@ -26,20 +26,12 @@ class TrackManager(var allSongPath: MutableList<String>) {
|
||||
val trackLenghStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
||||
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 ||
|
||||
trackLenghStr == null) {
|
||||
println("dd")
|
||||
}
|
||||
|
||||
val track = Track(id, trackTitle, trackArtist, trackAlbum, trackLength,
|
||||
art!!, musicPath)
|
||||
ByteArray(0), musicPath)
|
||||
dumpToDatabase(ctx, track)
|
||||
id++
|
||||
}
|
||||
|
||||
@@ -20,11 +20,10 @@ class TrackRepository(val context: Context) {
|
||||
val artist = columns.getValue("Artist").toString()
|
||||
val album = columns.getValue("Album").toString()
|
||||
val duration = columns.getValue("Duration").toString().toInt()
|
||||
val cover = columns.getValue("Cover").toString().toByteArray()
|
||||
val songPath = columns.getValue("FilePath").toString()
|
||||
|
||||
val track = Track(id.toString().toInt(), title.toString(),artist,album,
|
||||
duration,cover,songPath)
|
||||
duration, ByteArray(0),songPath)
|
||||
tracks.add(track)
|
||||
|
||||
return track
|
||||
@@ -41,11 +40,10 @@ class TrackRepository(val context: Context) {
|
||||
val artist = columns.getValue("Artist").toString()
|
||||
var album = columns.getValue("Album").toString()
|
||||
val duration = columns.getValue("Duration").toString().toInt()
|
||||
var cover = columns.getValue("Cover").toString().toByteArray()
|
||||
var filePath = columns.getValue("FilePath").toString()
|
||||
|
||||
val track = Track(id, title, artist, album, duration,
|
||||
cover, filePath)
|
||||
ByteArray(0), filePath)
|
||||
|
||||
return track
|
||||
}
|
||||
@@ -68,8 +66,7 @@ class TrackRepository(val context: Context) {
|
||||
"Album" to track.album,
|
||||
"Artist" to track.artist,
|
||||
"Duration" to track.length,
|
||||
"FilePath" to track.songPath,
|
||||
"Cover" to track.TrackCover)
|
||||
"FilePath" to track.songPath)
|
||||
}
|
||||
fun createSongCount(songCount: Int) = context.database.use {
|
||||
insert("TrackCount",
|
||||
|
||||
Reference in New Issue
Block a user