we all like correctness + faster + laziness, so we got it all!
correctness: do not do the join of all audio tables, so we still get those music without albums, artist or genres. faster: this is also faster, as there is less data comming in, and during db_song_copy() we do not have to handle album, artist and genre strings. laziness: do just when item requests such information. So if you open the list but never scrolls, just a few will be fetched. And the information is saved for future reuse. SVN revision: 52664
This commit is contained in:
parent
966f3e0bae
commit
e70a9acb21
|
@ -190,7 +190,7 @@ collections {
|
|||
|
||||
group { name: "elm/genlist/item_compress/song/default";
|
||||
alias: "elm/genlist/item_compress_odd/song/default";
|
||||
data.item: "labels" "text.title text.album-artist";
|
||||
data.item: "labels" "ejy.text.title ejy.text.album-artist";
|
||||
//data.item: "icons" "swallow.cover";
|
||||
parts {
|
||||
part {
|
||||
|
@ -203,7 +203,7 @@ collections {
|
|||
}
|
||||
|
||||
part {
|
||||
name: "text.title";
|
||||
name: "ejy.text.title";
|
||||
type: TEXT;
|
||||
mouse_events: 0;
|
||||
scale: 1;
|
||||
|
@ -217,7 +217,7 @@ collections {
|
|||
rel2 {
|
||||
relative: 1.0 0.0;
|
||||
offset: -5 -2;
|
||||
to_y: "text.album-artist";
|
||||
to_y: "ejy.text.album-artist";
|
||||
}
|
||||
text {
|
||||
font: "Sans:style=Bold";
|
||||
|
@ -234,13 +234,14 @@ collections {
|
|||
}
|
||||
|
||||
part {
|
||||
name: "text.album-artist";
|
||||
name: "ejy.text.album-artist";
|
||||
type: TEXT;
|
||||
mouse_events: 0;
|
||||
description {
|
||||
state: "default" 0.0;
|
||||
color: 128 128 128 255;
|
||||
align: 0.0 1.0;
|
||||
fixed: 1 1;
|
||||
rel1 {
|
||||
relative: 0.0 1.0;
|
||||
offset: 4 -3;
|
||||
|
@ -254,7 +255,7 @@ collections {
|
|||
size: 8;
|
||||
min: 0 1;
|
||||
align: 0.0 1.0;
|
||||
text: "Album";
|
||||
text: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,14 +284,14 @@ collections {
|
|||
signal: "elm,state,selected";
|
||||
source: "elm";
|
||||
action: STATE_SET "selected" 0.0;
|
||||
target: "text.title";
|
||||
target: "ejy.text.title";
|
||||
}
|
||||
program {
|
||||
name: "go_passive";
|
||||
signal: "elm,state,unselected";
|
||||
source: "elm";
|
||||
action: STATE_SET "default" 0.0;
|
||||
target: "text.title";
|
||||
target: "ejy.text.title";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
166
src/bin/db.c
166
src/bin/db.c
|
@ -12,6 +12,9 @@ struct _DB
|
|||
sqlite3_stmt *songs_get;
|
||||
sqlite3_stmt *album_songs_get;
|
||||
sqlite3_stmt *artist_songs_get;
|
||||
sqlite3_stmt *album_get;
|
||||
sqlite3_stmt *artist_get;
|
||||
sqlite3_stmt *genre_get;
|
||||
} stmt;
|
||||
};
|
||||
|
||||
|
@ -82,44 +85,36 @@ _db_stmts_compile(DB *db)
|
|||
C(songs_get,
|
||||
"SELECT files.id, files.path, files.size, "
|
||||
" audios.title, audios.album_id, audios.artist_id, audios.genre_id, "
|
||||
" audios.trackno, audios.rating, audios.playcnt, audios.length, "
|
||||
" audio_albums.name, audio_artists.name, audio_genres.name "
|
||||
"FROM audios, files, audio_albums, audio_artists, audio_genres "
|
||||
" audios.trackno, audios.rating, audios.playcnt, audios.length "
|
||||
"FROM audios, files "
|
||||
"WHERE "
|
||||
" files.id = audios.id AND "
|
||||
" audio_albums.id = audios.album_id AND "
|
||||
" audio_artists.id = audios.artist_id AND "
|
||||
" audio_genres.id = audios.genre_id "
|
||||
" files.id = audios.id "
|
||||
"ORDER BY UPPER(audios.title)");
|
||||
|
||||
C(album_songs_get,
|
||||
"SELECT files.id, files.path, files.size, "
|
||||
" audios.title, audios.album_id, audios.artist_id, audios.genre_id, "
|
||||
" audios.trackno, audios.rating, audios.playcnt, audios.length, "
|
||||
" audio_albums.name, audio_artists.name, audio_genres.name "
|
||||
"FROM audios, files, audio_albums, audio_artists, audio_genres "
|
||||
" audios.trackno, audios.rating, audios.playcnt, audios.length "
|
||||
"FROM audios, files "
|
||||
"WHERE "
|
||||
" files.id = audios.id AND "
|
||||
" audio_albums.id = audios.album_id AND "
|
||||
" audio_artists.id = audios.artist_id AND "
|
||||
" audio_genres.id = audios.genre_id AND "
|
||||
" audios.album_id = ? "
|
||||
"ORDER BY audios.trackno, UPPER(audios.title)");
|
||||
|
||||
C(artist_songs_get,
|
||||
"SELECT files.id, files.path, files.size, "
|
||||
" audios.title, audios.album_id, audios.artist_id, audios.genre_id, "
|
||||
" audios.trackno, audios.rating, audios.playcnt, audios.length, "
|
||||
" audio_albums.name, audio_artists.name, audio_genres.name "
|
||||
"FROM audios, files, audio_albums, audio_artists, audio_genres "
|
||||
" audios.trackno, audios.rating, audios.playcnt, audios.length "
|
||||
"FROM audios, files "
|
||||
"WHERE "
|
||||
" files.id = audios.id AND "
|
||||
" audio_albums.id = audios.album_id AND "
|
||||
" audio_artists.id = audios.artist_id AND "
|
||||
" audio_genres.id = audios.genre_id AND "
|
||||
" audios.artist_id = ? "
|
||||
"ORDER BY UPPER(audios.title)");
|
||||
|
||||
C(album_get, "SELECT name FROM audio_albums WHERE id = ?");
|
||||
C(artist_get, "SELECT name FROM audio_artists WHERE id = ?");
|
||||
C(genre_get, "SELECT name FROM audio_genres WHERE id = ?");
|
||||
|
||||
#undef C
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
@ -135,6 +130,9 @@ _db_stmts_finalize(DB *db)
|
|||
F(songs_get);
|
||||
F(album_songs_get);
|
||||
F(artist_songs_get);
|
||||
F(album_get);
|
||||
F(artist_get);
|
||||
F(genre_get);
|
||||
|
||||
#undef F
|
||||
return ret;
|
||||
|
@ -312,9 +310,6 @@ _db_iterator_songs_next(Eina_Iterator *iterator, void **data)
|
|||
INT(rating, 8);
|
||||
INT(playcnt, 9);
|
||||
INT(length, 10);
|
||||
STR(album, 11);
|
||||
STR(artist, 12);
|
||||
STR(genre, 13);
|
||||
|
||||
#undef STR
|
||||
#undef INT
|
||||
|
@ -408,6 +403,133 @@ db_artist_songs_get(DB *db, int64_t artist_id)
|
|||
return &it->base.base;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
db_song_album_fetch(DB *db, Song *song)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
Eina_Bool ret;
|
||||
int err;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(db, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(song, EINA_FALSE);
|
||||
if (song->flags.fetched_album) return EINA_TRUE;
|
||||
|
||||
stmt = db->stmt.album_get;
|
||||
if (!_db_stmt_bind_int64(stmt, 1, song->album_id))
|
||||
return EINA_FALSE;
|
||||
|
||||
err = sqlite3_step(stmt);
|
||||
if (err == SQLITE_ROW)
|
||||
{
|
||||
eina_stringshare_replace
|
||||
(&song->album, (const char *)sqlite3_column_text(stmt, 0));
|
||||
song->len.album = sqlite3_column_bytes(stmt, 0);
|
||||
ret = EINA_TRUE;
|
||||
}
|
||||
else if (err == SQLITE_DONE)
|
||||
{
|
||||
DBG("no album with id=%lld", (long long)song->album_id);
|
||||
eina_stringshare_replace(&song->album, NULL);
|
||||
song->len.album = 0;
|
||||
ret = EINA_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("could not query album with id=%lld: %s",
|
||||
(long long)song->album_id, sqlite3_errmsg(db->handle));
|
||||
ret = EINA_FALSE;
|
||||
}
|
||||
|
||||
_db_stmt_reset(stmt);
|
||||
song->flags.fetched_album = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
db_song_artist_fetch(DB *db, Song *song)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
Eina_Bool ret;
|
||||
int err;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(db, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(song, EINA_FALSE);
|
||||
if (song->flags.fetched_artist) return EINA_TRUE;
|
||||
|
||||
stmt = db->stmt.artist_get;
|
||||
if (!_db_stmt_bind_int64(stmt, 1, song->artist_id))
|
||||
return EINA_FALSE;
|
||||
|
||||
err = sqlite3_step(stmt);
|
||||
if (err == SQLITE_ROW)
|
||||
{
|
||||
eina_stringshare_replace
|
||||
(&song->artist, (const char *)sqlite3_column_text(stmt, 0));
|
||||
song->len.artist = sqlite3_column_bytes(stmt, 0);
|
||||
ret = EINA_TRUE;
|
||||
}
|
||||
else if (err == SQLITE_DONE)
|
||||
{
|
||||
DBG("no artist with id=%lld", (long long)song->artist_id);
|
||||
eina_stringshare_replace(&song->artist, NULL);
|
||||
song->len.artist = 0;
|
||||
ret = EINA_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("could not query artist with id=%lld: %s",
|
||||
(long long)song->artist_id, sqlite3_errmsg(db->handle));
|
||||
ret = EINA_FALSE;
|
||||
}
|
||||
|
||||
_db_stmt_reset(stmt);
|
||||
song->flags.fetched_artist = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
db_song_genre_fetch(DB *db, Song *song)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
Eina_Bool ret;
|
||||
int err;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(db, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(song, EINA_FALSE);
|
||||
if (song->flags.fetched_genre) return EINA_TRUE;
|
||||
|
||||
stmt = db->stmt.genre_get;
|
||||
if (!_db_stmt_bind_int64(stmt, 1, song->genre_id))
|
||||
return EINA_FALSE;
|
||||
|
||||
err = sqlite3_step(stmt);
|
||||
if (err == SQLITE_ROW)
|
||||
{
|
||||
eina_stringshare_replace
|
||||
(&song->genre, (const char *)sqlite3_column_text(stmt, 0));
|
||||
song->len.genre = sqlite3_column_bytes(stmt, 0);
|
||||
ret = EINA_TRUE;
|
||||
}
|
||||
else if (err == SQLITE_DONE)
|
||||
{
|
||||
DBG("no genre with id=%lld", (long long)song->genre_id);
|
||||
eina_stringshare_replace(&song->genre, NULL);
|
||||
song->len.genre = 0;
|
||||
ret = EINA_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("could not query genre with id=%lld: %s",
|
||||
(long long)song->genre_id, sqlite3_errmsg(db->handle));
|
||||
ret = EINA_FALSE;
|
||||
}
|
||||
|
||||
_db_stmt_reset(stmt);
|
||||
song->flags.fetched_genre = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
|
106
src/bin/page.c
106
src/bin/page.c
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
/* number of songs to populate at once before going back to mainloop */
|
||||
#define PAGE_SONGS_POPULATE_ITERATION_COUNT (128)
|
||||
#define PAGE_SONGS_POPULATE_ITERATION_COUNT (64)
|
||||
|
||||
typedef struct _Page
|
||||
{
|
||||
|
@ -32,15 +32,36 @@ typedef struct _Page
|
|||
|
||||
|
||||
static char *
|
||||
_song_item_label_get(void *data, Evas_Object *list __UNUSED__, const char *part)
|
||||
_song_item_label_get(void *data, Evas_Object *list, const char *part)
|
||||
{
|
||||
Song *song = data;
|
||||
|
||||
if (!strcmp(part, "text.title"))
|
||||
/* check if matches protocol */
|
||||
if (strncmp(part, "ejy.text.", sizeof("ejy.text.") - 1) != 0)
|
||||
return NULL;
|
||||
part += sizeof("ejy.text.") - 1;
|
||||
|
||||
if (!strcmp(part, "title"))
|
||||
return strdup(song->title);
|
||||
else if (!strcmp(part, "text.album-artist"))
|
||||
else if (!strcmp(part, "trackno-title"))
|
||||
{
|
||||
char *str;
|
||||
if (song->trackno < 1) return strdup(song->title);
|
||||
if (asprintf(&str, "%d - %s", song->trackno, song->title) > 0)
|
||||
return str;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(part, "album-artist"))
|
||||
{
|
||||
char *str;
|
||||
|
||||
if ((!song->flags.fetched_album) || (!song->flags.fetched_artist))
|
||||
{
|
||||
DB *db = evas_object_data_get(list, "_enjoy_db");
|
||||
db_song_album_fetch(db, song);
|
||||
db_song_artist_fetch(db, song);
|
||||
}
|
||||
|
||||
if ((!song->album) && (!song->artist)) return NULL;
|
||||
else if (!song->album) return strdup(song->artist);
|
||||
else if (!song->artist) return strdup(song->album);
|
||||
|
@ -49,10 +70,74 @@ _song_item_label_get(void *data, Evas_Object *list __UNUSED__, const char *part)
|
|||
return str;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(part, "text.album"))
|
||||
return song->album ? strdup(song->album) : NULL;
|
||||
else if (!strcmp(part, "text.artist"))
|
||||
return song->artist ? strdup(song->artist) : NULL;
|
||||
else if (!strcmp(part, "album"))
|
||||
{
|
||||
if (!song->flags.fetched_album)
|
||||
{
|
||||
DB *db = evas_object_data_get(list, "_enjoy_db");
|
||||
db_song_album_fetch(db, song);
|
||||
}
|
||||
return song->album ? strdup(song->album) : NULL;
|
||||
}
|
||||
else if (!strcmp(part, "artist"))
|
||||
{
|
||||
if (!song->flags.fetched_artist)
|
||||
{
|
||||
DB *db = evas_object_data_get(list, "_enjoy_db");
|
||||
db_song_artist_fetch(db, song);
|
||||
}
|
||||
return song->artist ? strdup(song->artist) : NULL;
|
||||
}
|
||||
else if (!strcmp(part, "genre"))
|
||||
{
|
||||
if (!song->flags.fetched_genre)
|
||||
{
|
||||
DB *db = evas_object_data_get(list, "_enjoy_db");
|
||||
db_song_genre_fetch(db, song);
|
||||
}
|
||||
return song->genre ? strdup(song->genre) : NULL;
|
||||
}
|
||||
else if (!strcmp(part, "trackno"))
|
||||
{
|
||||
char *str;
|
||||
if (song->trackno < 1) return NULL;
|
||||
if (asprintf(&str, "%d", song->trackno) > 0)
|
||||
return str;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(part, "playcnt"))
|
||||
{
|
||||
char *str;
|
||||
if (song->playcnt < 1) return NULL;
|
||||
if (asprintf(&str, "%d", song->playcnt) > 0)
|
||||
return str;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(part, "rating"))
|
||||
{
|
||||
char *str;
|
||||
if (song->rating < 1) return NULL;
|
||||
if (asprintf(&str, "%d", song->rating) > 0)
|
||||
return str;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(part, "length"))
|
||||
{
|
||||
char *str;
|
||||
int len;
|
||||
if (song->length < 1) return NULL;
|
||||
if (song->length < 60)
|
||||
len = asprintf(&str, "%d", song->length);
|
||||
else if (song->length < 60 * 60)
|
||||
len = asprintf(&str, "%d:%02d", song->length / 60, song->length % 60);
|
||||
else
|
||||
len = asprintf(&str, "%d:%02d:%02d",
|
||||
song->length / (60 * 60),
|
||||
(song->length / 60) % 60,
|
||||
song->length % 60);
|
||||
if (len > 0) return str;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -188,14 +273,15 @@ page_songs_add(Evas_Object *parent, Eina_Iterator *it, const char *title)
|
|||
elm_genlist_bounce_set(page->list, EINA_FALSE, EINA_TRUE);
|
||||
elm_genlist_horizontal_mode_set(page->list, ELM_LIST_COMPRESS);
|
||||
elm_genlist_compress_mode_set(page->list, EINA_TRUE);
|
||||
elm_genlist_block_count_set(page->list, 1024);
|
||||
elm_genlist_block_count_set(page->list, 256);
|
||||
evas_object_data_set(page->list, "_enjoy_db",
|
||||
eina_iterator_container_get(it));
|
||||
|
||||
evas_object_smart_callback_add
|
||||
(page->list, "selected", _page_songs_selected, page);
|
||||
|
||||
s = edje_object_data_get(page->edje, "homogeneous");
|
||||
elm_genlist_homogeneous_set(page->list, s ? !!atoi(s) : EINA_FALSE);
|
||||
printf("genlist homogeneous: %d\n", elm_genlist_homogeneous_get(page->list));
|
||||
|
||||
elm_layout_content_set(obj, "ejy.swallow.list", page->list);
|
||||
|
||||
|
|
|
@ -75,6 +75,11 @@ struct _Song
|
|||
unsigned int artist;
|
||||
unsigned int genre;
|
||||
} len; /* strlen of string fields */
|
||||
struct { /* not from db, for runtime use */
|
||||
Eina_Bool fetched_album:1;
|
||||
Eina_Bool fetched_artist:1;
|
||||
Eina_Bool fetched_genre:1;
|
||||
} flags;
|
||||
};
|
||||
|
||||
Eina_Iterator *db_songs_get(DB *db); /* walks over 'const Song*' */
|
||||
|
@ -82,6 +87,9 @@ Song *db_song_copy(const Song *orig);
|
|||
void db_song_free(Song *song);
|
||||
Eina_Bool db_song_rating_set(DB *db, Song *song, int rating);
|
||||
Eina_Bool db_song_length_set(DB *db, Song *song, int length);
|
||||
Eina_Bool db_song_album_fetch(DB *db, Song *song);
|
||||
Eina_Bool db_song_artist_fetch(DB *db, Song *song);
|
||||
Eina_Bool db_song_genre_fetch(DB *db, Song *song);
|
||||
|
||||
Eina_Iterator *db_album_songs_get(DB *db, int64_t album_id);
|
||||
Eina_Iterator *db_artist_songs_get(DB *db, int64_t artist_id);
|
||||
|
|
Loading…
Reference in New Issue