diff --git a/.idea/Mear.iml b/.idea/Mear.iml index cd61b1c..0fbbc63 100644 --- a/.idea/Mear.iml +++ b/.idea/Mear.iml @@ -1,5 +1,13 @@ + + + + + + diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 51cd9eb..ec56d95 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 95f7c83..138c4f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + + + - - \ No newline at end of file diff --git a/app/src/main/java/com/example/mear/AppCompatPreferenceActivity.kt b/app/src/main/java/com/example/mear/AppCompatPreferenceActivity.kt new file mode 100644 index 0000000..42d1989 --- /dev/null +++ b/app/src/main/java/com/example/mear/AppCompatPreferenceActivity.kt @@ -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) + } +} diff --git a/app/src/main/java/com/example/mear/MainActivity.kt b/app/src/main/java/com/example/mear/MainActivity.kt index a580d76..ca79c19 100644 --- a/app/src/main/java/com/example/mear/MainActivity.kt +++ b/app/src/main/java/com/example/mear/MainActivity.kt @@ -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 { diff --git a/app/src/main/java/com/example/mear/SettingsActivity.kt b/app/src/main/java/com/example/mear/SettingsActivity.kt new file mode 100644 index 0000000..33de420 --- /dev/null +++ b/app/src/main/java/com/example/mear/SettingsActivity.kt @@ -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) { + 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, "") + ) + } + } +} diff --git a/app/src/main/java/com/example/mear/management/DatabaseManager.kt b/app/src/main/java/com/example/mear/management/DatabaseManager.kt index b9d58ef..480c1e8 100644 --- a/app/src/main/java/com/example/mear/management/DatabaseManager.kt +++ b/app/src/main/java/com/example/mear/management/DatabaseManager.kt @@ -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, diff --git a/app/src/main/java/com/example/mear/management/TrackManager.kt b/app/src/main/java/com/example/mear/management/TrackManager.kt index f731cd1..569c207 100644 --- a/app/src/main/java/com/example/mear/management/TrackManager.kt +++ b/app/src/main/java/com/example/mear/management/TrackManager.kt @@ -26,20 +26,12 @@ class TrackManager(var allSongPath: MutableList) { 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++ } diff --git a/app/src/main/java/com/example/mear/repositories/TrackRepository.kt b/app/src/main/java/com/example/mear/repositories/TrackRepository.kt index e4d9544..3d5a3be 100644 --- a/app/src/main/java/com/example/mear/repositories/TrackRepository.kt +++ b/app/src/main/java/com/example/mear/repositories/TrackRepository.kt @@ -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", diff --git a/app/src/main/res/drawable/ic_info_black_24dp.xml b/app/src/main/res/drawable/ic_info_black_24dp.xml new file mode 100644 index 0000000..8024b5b --- /dev/null +++ b/app/src/main/res/drawable/ic_info_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..14f20f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml new file mode 100644 index 0000000..478aa98 --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 9bf88d8..1ff260a 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -16,7 +16,7 @@ tools:layout_editor_absoluteX="0dp"> + android:layout_width="21dp"/>