@@ -1,29 +1,28 @@
|
||||
package com.example.mear.activities
|
||||
|
||||
import android.graphics.Color
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.media.MediaPlayer
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.text.format.Time
|
||||
import com.example.mear.R
|
||||
|
||||
import java.lang.Exception
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.content_main.*
|
||||
import kotlin.io.*
|
||||
import kotlin.random.Random
|
||||
|
||||
import com.example.mear.management.MusicFiles
|
||||
import com.example.mear.management.TrackManager
|
||||
import com.example.mear.repositories.TrackRepository
|
||||
import kotlinx.android.synthetic.main.fragment_play_controls.*
|
||||
import kotlinx.android.synthetic.main.fragment_track_cover.*
|
||||
import kotlinx.android.synthetic.main.fragment_track_details.*
|
||||
import kotlinx.android.synthetic.main.fragment_track_elapsing.*
|
||||
import kotlinx.android.synthetic.main.fragment_track_flow.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.io.*
|
||||
import kotlin.random.Random
|
||||
|
||||
import com.example.mear.R
|
||||
import com.example.mear.repositories.TrackRepository
|
||||
import org.jetbrains.anko.image
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@@ -32,8 +31,6 @@ class MainActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_main)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
//loadTracks(loadSongPaths())
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
@@ -59,6 +56,18 @@ class MainActivity : AppCompatActivity() {
|
||||
ShuffleTracks.setOnClickListener {
|
||||
toggleShuffle()
|
||||
}
|
||||
SettingsLink.setOnClickListener {
|
||||
val intent = Intent(this, SettingsActivity::class.java)
|
||||
try {
|
||||
|
||||
|
||||
startActivity(intent)
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
val exMsg = ex.message
|
||||
println(exMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun initializeCompletionListener() {
|
||||
trackPlayer!!.setOnCompletionListener {
|
||||
@@ -100,10 +109,10 @@ class MainActivity : AppCompatActivity() {
|
||||
try {
|
||||
if (!trackPlayer!!.isPlaying) {
|
||||
trackPlayer!!.start()
|
||||
configureTrackDisplay()
|
||||
} else {
|
||||
trackPlayer!!.pause()
|
||||
}
|
||||
configureTrackDisplay()
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
val exMsg = ex.message
|
||||
@@ -153,39 +162,53 @@ class MainActivity : AppCompatActivity() {
|
||||
PreviousTrack.isEnabled = true
|
||||
}
|
||||
private fun configureTrackDisplay() {
|
||||
configurePlayControlsDisplay()
|
||||
val currTrack = TrackRepository(this).getTrack(currentSong!!)
|
||||
val trackTitle = currTrack.title
|
||||
val artistTitle = currTrack.artist
|
||||
val albumTitle = currTrack.album
|
||||
var trackDuration = currTrack.length
|
||||
val trackDuration = currTrack.length
|
||||
var trackCover: ByteArray? = null
|
||||
val dur = String.format("%02d:%02d", TimeUnit.SECONDS.toMinutes(trackDuration.toLong()),
|
||||
(trackDuration % 60)
|
||||
)
|
||||
|
||||
var mmr = MediaMetadataRetriever()
|
||||
val mmr = MediaMetadataRetriever()
|
||||
mmr.setDataSource(currTrack.songPath)
|
||||
|
||||
if (mmr.embeddedPicture != null) {
|
||||
trackCover = mmr.embeddedPicture
|
||||
}
|
||||
|
||||
TrackTitle.setText(null)
|
||||
ArtistTitle.setText(null)
|
||||
AlbumTitle.setText(null)
|
||||
CurrentPosition.setText(null)
|
||||
TrackTitle.text = null
|
||||
ArtistTitle.text = null
|
||||
AlbumTitle.text = null
|
||||
CurrentPosition.text = null
|
||||
TrackCover.setImageBitmap(null)
|
||||
|
||||
TrackTitle.setText(trackTitle)
|
||||
ArtistTitle.setText(artistTitle)
|
||||
AlbumTitle.setText(albumTitle)
|
||||
TrackDuration.setText(dur)
|
||||
TrackTitle.text = trackTitle
|
||||
ArtistTitle.text = artistTitle
|
||||
AlbumTitle.text = albumTitle
|
||||
TrackDuration.text = dur
|
||||
if (trackCover != null) {
|
||||
val songImage = BitmapFactory
|
||||
.decodeByteArray(trackCover, 0, trackCover.size)
|
||||
TrackCover.setImageBitmap(songImage)
|
||||
}
|
||||
}
|
||||
private fun configurePlayControlsDisplay() {
|
||||
PlayTrack.background = null
|
||||
PlayTrack.colorFilter = null
|
||||
|
||||
if (!trackPlayer!!.isPlaying) {
|
||||
PlayTrack.setImageResource(android.R.drawable.ic_media_pause)
|
||||
PlayTrack.setColorFilter(Color.RED)
|
||||
}
|
||||
else {
|
||||
PlayTrack.setImageResource(android.R.drawable.ic_media_play)
|
||||
PlayTrack.setColorFilter(Color.GREEN)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchSongIndex(playType: PlayTypes): Int {
|
||||
var songIndex: Int? = null
|
||||
@@ -227,33 +250,11 @@ class MainActivity : AppCompatActivity() {
|
||||
return songIndex!!
|
||||
}
|
||||
|
||||
private fun loadSongPaths(): MutableList<String> {
|
||||
val demoPath = Environment.getExternalStorageDirectory()
|
||||
val mfPaths = MusicFiles(demoPath)
|
||||
mfPaths.loadAllMusicPaths()
|
||||
val allSongs = mfPaths.allSongs
|
||||
|
||||
return allSongs!!
|
||||
}
|
||||
private fun loadTracks(allSongs: MutableList<String>) {
|
||||
try {
|
||||
val trackMgr = TrackManager(allSongs)
|
||||
songCount = trackMgr.configureTracks(this)
|
||||
|
||||
songCount = TrackRepository(this).getSongCount()
|
||||
|
||||
currentSong = fetchSongIndex(PlayTypes.PlaySong)
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
val exMsg = ex.message
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var trackPlayer: MediaPlayer? = null
|
||||
private var currentSong: Int? = null
|
||||
private var playerInitialized: Boolean? = null
|
||||
private var shuffleOn: Boolean? = null
|
||||
private var playerInitialized: Boolean? = false
|
||||
private var shuffleOn: Boolean? = false
|
||||
private var songCount: Int? = null
|
||||
|
||||
private enum class PlayTypes {
|
||||
|
||||
@@ -1,255 +1,56 @@
|
||||
package com.example.mear.activities
|
||||
|
||||
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
|
||||
import com.example.mear.AppCompatPreferenceActivity
|
||||
import com.example.mear.R
|
||||
import android.os.Environment
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
import java.lang.Exception
|
||||
import kotlinx.android.synthetic.main.activity_settings.*
|
||||
import kotlinx.android.synthetic.main.content_settings.*
|
||||
|
||||
import com.example.mear.R
|
||||
import com.example.mear.management.MusicFiles
|
||||
import com.example.mear.management.TrackManager
|
||||
import com.example.mear.repositories.TrackRepository
|
||||
|
||||
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setupActionBar()
|
||||
}
|
||||
setContentView(R.layout.activity_settings)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
RefreshLibrary.setOnClickListener {
|
||||
updateLibrary()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
private fun loadSongPaths(): MutableList<String> {
|
||||
val demoPath = Environment.getExternalStorageDirectory()
|
||||
val mfPaths = MusicFiles(demoPath)
|
||||
mfPaths.loadAllMusicPaths()
|
||||
val allSongs = mfPaths.allSongs
|
||||
|
||||
return allSongs!!
|
||||
}
|
||||
private fun loadTracks(allSongs: MutableList<String>) {
|
||||
try {
|
||||
TrackRepository(this).delete()
|
||||
val trackMgr = TrackManager(allSongs)
|
||||
}
|
||||
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)
|
||||
catch (ex: Exception) {
|
||||
val exMsg = ex.message
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, "")
|
||||
)
|
||||
}
|
||||
private fun updateLibrary() {
|
||||
loadTracks(loadSongPaths())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class DatabaseManager(ctx: Context): ManagedSQLiteOpenHelper(ctx, "Mear",
|
||||
"TrackId" to INTEGER
|
||||
)
|
||||
db!!.createTable(
|
||||
"Settings", true,
|
||||
"SettingsActivity", true,
|
||||
"Id" to INTEGER + PRIMARY_KEY + UNIQUE,
|
||||
"DarkTheme" to org.jetbrains.anko.db.REAL
|
||||
)
|
||||
@@ -56,7 +56,7 @@ class DatabaseManager(ctx: Context): ManagedSQLiteOpenHelper(ctx, "Mear",
|
||||
db!!.dropTable("Track")
|
||||
db!!.dropTable("TrackCount")
|
||||
db!!.dropTable("PlayCount")
|
||||
db!!.dropTable("Settings")
|
||||
db!!.dropTable("SettingsActivity")
|
||||
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
|
||||
@@ -42,16 +42,6 @@ class TrackManager(var allSongPath: MutableList<String>) {
|
||||
}
|
||||
return id.dec()
|
||||
}
|
||||
fun dumpToDatabase(ctx: Context) {
|
||||
TrackRepository(ctx).delete()
|
||||
for (songData in allTracks!!) {
|
||||
TrackRepository(ctx).insertTrack(songData)
|
||||
allTracks!!.removeAt(songData.id )
|
||||
}
|
||||
}
|
||||
fun deleteTable(ctx: Context) {
|
||||
TrackRepository(ctx).delete()
|
||||
}
|
||||
private fun dumpToDatabase(ctx: Context, track: Track) {
|
||||
TrackRepository(ctx).insertTrack(track)
|
||||
PlayCountRepository(ctx).insertPlayCount(track)
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.example.mear.models.Settings
|
||||
|
||||
class SettingRepository(val context: Context) {
|
||||
fun getSettings(id: Int): Settings = context.database.use {
|
||||
select("Settings").where("Id = $id")
|
||||
select("SettingsActivity").where("Id = $id")
|
||||
.parseSingle(object: MapRowParser<Settings>{
|
||||
override fun parseRow(columns: Map<String, Any?>): Settings {
|
||||
val id = columns.getValue("Id").toString().toInt()
|
||||
@@ -22,20 +22,20 @@ class SettingRepository(val context: Context) {
|
||||
})
|
||||
}
|
||||
fun insertSettings(settings: Settings) = context.database.use {
|
||||
insert("Settings",
|
||||
insert("SettingsActivity",
|
||||
"Id" to settings.id,
|
||||
"DarkTheme" to false)
|
||||
}
|
||||
fun updateSettings(settings: Settings) = context.database.use {
|
||||
update("Settings",
|
||||
update("SettingsActivity",
|
||||
"DarkTheme" to settings.darkTheme)
|
||||
.where("Id = {settingId}", "settingId" to settings.id).exec()
|
||||
}
|
||||
|
||||
fun delete(table: Settings?) = context.database.use {
|
||||
delete("Settings", whereClause = "id = {$table.id}")
|
||||
delete("SettingsActivity", whereClause = "id = {$table.id}")
|
||||
}
|
||||
fun delete() = context.database.use {
|
||||
delete("Settings")
|
||||
delete("SettingsActivity")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user