Lifecycle Aware
- ViewModel
- LiveData
Local Storage
- Room
View Components
- Fragment
- RecyclerView
Automatic highlighting of lyrics
- click 'display' when in view mode
- Undo/Redo stack
- Fields for Essential Song Metadata
- Share
- Delete
When inspiration hits
See the structure of the lyrics by clicking 'display' in the action bar.
- Verses appear plain with no color span
- Chorus stanzas and repeating lines are highlighted
- Emphasis
- Make Distinct from Verse
Lyrics from https://www.lyricsondemand.com
- Scheme
- Randomize
-
Convert query: String to tokens: Collection
// Delimit the query on ',' val tokens = java.lang.String(query).split(",") val trimmedTokens = tokens.map { var r = if (it != null) java.lang.String(it).trim() else null if (r?.isEmpty() == true) r = null r } val searchableTokens = trimmedTokens.filterNotNull()
-
Declare a function that searches field in searchableTokens
fun containsPartialMatch(field: String): Boolean { return searchableTokens.find { tk -> field.contains(tk, ignoreCase = true) } != null }
-
Return list items that containPartialMatch( field )
return listItems.filter { when (filterId) { R.id.menu_filter_artist -> containsPartialMatch(it.artist) R.id.menu_filter_album -> containsPartialMatch(it.album) R.id.menu_filter_track -> containsPartialMatch(it.trackTitle) // Filter on 'any' case else -> containsPartialMatch(it.artist) || containsPartialMatch(it.album) || containsPartialMatch(it.trackTitle) } }
-
Get a ViewModel for the detail view scoped to the activity
songLyricsDetailViewModel = ViewModelProviders.of(getActivity()).get(SongLyricDetailItemViewModel.class);
-
Ensure the ViewModel, and underlying Repository, are connected to sqlite using Room
songLyricsDetailViewModel.setSongLyricsDao(LyricDatabaseHelper .getSongLyricDatabase(getActivity()) .songLyricsDao());
Song Lyrics entities are accessed by SongLyricsDao, analogous to a cursor. LyricsDatabaseHelper delegates opening the database
-
Observe Changes in SongLyrics LiveData to the view in LyricFragment
songLyricsObserver = new Observer<SongLyrics>() { @Override public void onChanged(@Nullable SongLyrics songLyrics) { // Update views with content from songLyrics object trackInfo.get(R.id.title).setText(songLyrics.getTrackTitle()); . . . lyrics.setText(new SpannableString(songLyrics.getLyrics()), TextView.BufferType.EDITABLE); } LiveData<SongLyrics> songLyricsLiveData = songLyricsDetailViewModel.getSongLyrics(); // Set the observer on the live data songLyricsLiveData.observe(this, songLyricsObserver);
songLyricDatabase = Room.databaseBuilder(context,
SongLyricDatabase.class, DATABASE_NAME)
.build();
The databaseBuilder is used in a typical setup. Optionally, the database can be set up to allow access to the main thread and forcing recreation without a migration
Example
songLyricDatabase = Room.databaseBuilder(context,
SongLyricDatabase.class, DATABASE_NAME)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();