mirror of
https://github.com/clangen/musikcube.git
synced 2025-01-30 06:32:36 +00:00
Added buffering indicator to the android client, and also tweaked a
couple transcoder settings keys. Also updated some variable names -- we're not decoding, we're encoding!
This commit is contained in:
parent
45811b90a0
commit
0aff544712
@ -41,18 +41,18 @@ namespace defaults {
|
|||||||
static const int websocket_server_port = 7905;
|
static const int websocket_server_port = 7905;
|
||||||
static const int http_server_port = 7906;
|
static const int http_server_port = 7906;
|
||||||
static const std::string password = "";
|
static const std::string password = "";
|
||||||
static const int http_server_transcoder_cache_count = 50;
|
static const int transcoder_cache_count = 50;
|
||||||
static const bool http_server_transcoder_synchronous = false;
|
static const bool transcoder_synchronous = false;
|
||||||
static const bool http_server_transcoder_synchronous_fallback = true;
|
static const bool transcoder_synchronous_fallback = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace prefs {
|
namespace prefs {
|
||||||
static const std::string websocket_server_port = "websocket_server_port";
|
static const std::string websocket_server_port = "websocket_server_port";
|
||||||
static const std::string http_server_enabled = "http_server_enabled";
|
static const std::string http_server_enabled = "http_server_enabled";
|
||||||
static const std::string http_server_port = "http_server_port";
|
static const std::string http_server_port = "http_server_port";
|
||||||
static const std::string http_server_transcoder_cache_count = "http_server_transcoder_cache_count";
|
static const std::string transcoder_cache_count = "transcoder_cache_count";
|
||||||
static const std::string http_server_transcoder_synchronous = "http_server_transcoder_synchronous";
|
static const std::string transcoder_synchronous = "transcoder_synchronous";
|
||||||
static const std::string http_server_transcoder_synchronous_fallback = "http_server_transcoder_synchronous_fallback";
|
static const std::string transcoder_synchronous_fallback = "transcoder_synchronous_fallback";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace message {
|
namespace message {
|
||||||
|
@ -328,8 +328,8 @@ int HttpServer::HandleRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (false && server->context.prefs->GetBool(
|
if (false && server->context.prefs->GetBool(
|
||||||
prefs::http_server_transcoder_synchronous_fallback.c_str(),
|
prefs::transcoder_synchronous_fallback.c_str(),
|
||||||
defaults::http_server_transcoder_synchronous_fallback))
|
defaults::transcoder_synchronous_fallback))
|
||||||
{
|
{
|
||||||
/* if we're allowed, fall back to synchronous transcoding. we'll block
|
/* if we're allowed, fall back to synchronous transcoding. we'll block
|
||||||
here until the entire file has been converted and cached */
|
here until the entire file has been converted and cached */
|
||||||
|
@ -46,17 +46,15 @@ static std::string cachePath(Context& context) {
|
|||||||
context.environment->GetPath(PathType::PathData, buf, sizeof(buf));
|
context.environment->GetPath(PathType::PathData, buf, sizeof(buf));
|
||||||
std::string path = std::string(buf) + "/transcode/";
|
std::string path = std::string(buf) + "/transcode/";
|
||||||
|
|
||||||
if (!boost::filesystem::exists(path)) {
|
if (!exists(path)) {
|
||||||
boost::filesystem::create_directories(path);
|
create_directories(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iterateTranscodeCache(Context& context, std::function<void(boost::filesystem::path)> cb) {
|
static void iterateTranscodeCache(Context& context, std::function<void(path)> cb) {
|
||||||
if (cb) {
|
if (cb) {
|
||||||
using namespace boost::filesystem;
|
|
||||||
|
|
||||||
directory_iterator end;
|
directory_iterator end;
|
||||||
directory_iterator file(cachePath(context));
|
directory_iterator file(cachePath(context));
|
||||||
|
|
||||||
@ -70,32 +68,32 @@ static void iterateTranscodeCache(Context& context, std::function<void(boost::fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Transcoder::RemoveTempTranscodeFiles(Context& context) {
|
void Transcoder::RemoveTempTranscodeFiles(Context& context) {
|
||||||
iterateTranscodeCache(context, [](boost::filesystem::path p) {
|
iterateTranscodeCache(context, [](path p) {
|
||||||
if (p.extension().string() == ".tmp") {
|
if (p.extension().string() == ".tmp") {
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
boost::filesystem::remove(p, ec);
|
remove(p, ec);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transcoder::PruneTranscodeCache(Context& context) {
|
void Transcoder::PruneTranscodeCache(Context& context) {
|
||||||
std::map<time_t, boost::filesystem::path> sorted;
|
std::map<time_t, path> sorted;
|
||||||
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
iterateTranscodeCache(context, [&sorted, &ec](boost::filesystem::path p) {
|
iterateTranscodeCache(context, [&sorted, &ec](path p) {
|
||||||
sorted[boost::filesystem::last_write_time(p, ec)] = p;
|
sorted[last_write_time(p, ec)] = p;
|
||||||
});
|
});
|
||||||
|
|
||||||
int maxSize = context.prefs->GetInt(
|
int maxSize = context.prefs->GetInt(
|
||||||
prefs::http_server_transcoder_cache_count.c_str(),
|
prefs::transcoder_cache_count.c_str(),
|
||||||
defaults::http_server_transcoder_cache_count);
|
defaults::transcoder_cache_count);
|
||||||
|
|
||||||
int extra = (int) sorted.size() - (maxSize - 1);
|
int extra = (int) sorted.size() - (maxSize - 1);
|
||||||
auto it = sorted.begin();
|
auto it = sorted.begin();
|
||||||
while (extra > 0 && it != sorted.end()) {
|
while (extra > 0 && it != sorted.end()) {
|
||||||
auto p = it->second;
|
auto p = it->second;
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
if (boost::filesystem::remove(p, ec)) {
|
if (remove(p, ec)) {
|
||||||
--extra;
|
--extra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,15 +114,15 @@ static void getTempAndFinalFilename(
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
tempFn = finalFn + "." + std::to_string(rand()) + ".tmp";
|
tempFn = finalFn + "." + std::to_string(rand()) + ".tmp";
|
||||||
} while (boost::filesystem::exists(tempFn));
|
} while (exists(tempFn));
|
||||||
}
|
}
|
||||||
|
|
||||||
IDataStream* Transcoder::Transcode(
|
IDataStream* Transcoder::Transcode(
|
||||||
Context& context, const std::string& uri, size_t bitrate)
|
Context& context, const std::string& uri, size_t bitrate)
|
||||||
{
|
{
|
||||||
if (context.prefs->GetBool(
|
if (context.prefs->GetBool(
|
||||||
prefs::http_server_transcoder_synchronous.c_str(),
|
prefs::transcoder_synchronous.c_str(),
|
||||||
defaults::http_server_transcoder_synchronous))
|
defaults::transcoder_synchronous))
|
||||||
{
|
{
|
||||||
return TranscodeAndWait(context, uri, bitrate);
|
return TranscodeAndWait(context, uri, bitrate);
|
||||||
}
|
}
|
||||||
|
@ -176,43 +176,43 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead)
|
|||||||
size_t numSamples = pcmBuffer->Samples() / pcmBuffer->Channels();
|
size_t numSamples = pcmBuffer->Samples() / pcmBuffer->Channels();
|
||||||
size_t requiredBytes = (size_t) (1.25 * (float)numSamples + 7200.0);
|
size_t requiredBytes = (size_t) (1.25 * (float)numSamples + 7200.0);
|
||||||
|
|
||||||
decodedBytes.realloc(requiredBytes);
|
encodedBytes.realloc(requiredBytes);
|
||||||
|
|
||||||
/* decode PCM -> MP3 */
|
/* encode PCM -> MP3 */
|
||||||
int decodeCount =
|
int encodeCount =
|
||||||
lame_encode_buffer_interleaved_ieee_float(
|
lame_encode_buffer_interleaved_ieee_float(
|
||||||
lame,
|
lame,
|
||||||
pcmBuffer->BufferPointer(),
|
pcmBuffer->BufferPointer(),
|
||||||
numSamples,
|
numSamples,
|
||||||
decodedBytes.data,
|
encodedBytes.data,
|
||||||
decodedBytes.length);
|
encodedBytes.length);
|
||||||
|
|
||||||
if (decodeCount < 0) {
|
if (encodeCount < 0) {
|
||||||
goto internal_error;
|
goto internal_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedBytes.length = (size_t) decodeCount;
|
encodedBytes.length = (size_t)encodeCount;
|
||||||
|
|
||||||
/* if we got something, let's write it to the output buffer */
|
/* if we got something, let's write it to the output buffer */
|
||||||
if (decodedBytes.length) {
|
if (encodedBytes.length) {
|
||||||
size_t toWrite = std::min(
|
size_t toWrite = std::min(
|
||||||
decodedBytes.length,
|
encodedBytes.length,
|
||||||
(size_t)(bytesToRead - bytesWritten));
|
(size_t)(bytesToRead - bytesWritten));
|
||||||
|
|
||||||
memcpy(dst + bytesWritten, decodedBytes.data, toWrite);
|
memcpy(dst + bytesWritten, encodedBytes.data, toWrite);
|
||||||
|
|
||||||
if (this->outFile) {
|
if (this->outFile) {
|
||||||
fwrite(decodedBytes.data, 1, toWrite, this->outFile);
|
fwrite(encodedBytes.data, 1, toWrite, this->outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedBytes.inc(toWrite);
|
encodedBytes.inc(toWrite);
|
||||||
bytesWritten += toWrite;
|
bytesWritten += toWrite;
|
||||||
|
|
||||||
/* if we have decoded bytes still available, that means the
|
/* if we have decoded bytes still available, that means the
|
||||||
output buffer is exhausted. swap it into the spillover buffer
|
output buffer is exhausted. swap it into the spillover buffer
|
||||||
so it can be finalized the next time through. */
|
so it can be finalized the next time through. */
|
||||||
if (decodedBytes.avail()) {
|
if (encodedBytes.avail()) {
|
||||||
spillover.swap(decodedBytes);
|
spillover.swap(encodedBytes);
|
||||||
this->position += bytesWritten;
|
this->position += bytesWritten;
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
@ -228,17 +228,17 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead)
|
|||||||
|
|
||||||
/* finalize */
|
/* finalize */
|
||||||
if (bytesWritten == 0) {
|
if (bytesWritten == 0) {
|
||||||
decodedBytes.reset();
|
encodedBytes.reset();
|
||||||
|
|
||||||
size_t count = lame_encode_flush(
|
size_t count = lame_encode_flush(
|
||||||
lame,
|
lame,
|
||||||
decodedBytes.data,
|
encodedBytes.data,
|
||||||
decodedBytes.length);
|
encodedBytes.length);
|
||||||
|
|
||||||
memcpy(dst + bytesWritten, decodedBytes.data, count);
|
memcpy(dst + bytesWritten, encodedBytes.data, count);
|
||||||
|
|
||||||
if (this->outFile) {
|
if (this->outFile) {
|
||||||
fwrite(decodedBytes.data, 1, count, this->outFile);
|
fwrite(encodedBytes.data, 1, count, this->outFile);
|
||||||
fclose(this->outFile);
|
fclose(this->outFile);
|
||||||
this->outFile = nullptr;
|
this->outFile = nullptr;
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ class TranscodingDataStream : public musik::core::sdk::IDataStream {
|
|||||||
size_t offset, length, rawLength;
|
size_t offset, length, rawLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
ByteBuffer decodedBytes;
|
ByteBuffer encodedBytes;
|
||||||
ByteBuffer spillover;
|
ByteBuffer spillover;
|
||||||
size_t bitrate;
|
size_t bitrate;
|
||||||
bool eof;
|
bool eof;
|
||||||
|
@ -159,9 +159,9 @@ extern "C" DLL_EXPORT void SetPreferences(musik::core::sdk::IPreferences* prefs)
|
|||||||
prefs->GetInt(prefs::http_server_port.c_str(), defaults::http_server_port);
|
prefs->GetInt(prefs::http_server_port.c_str(), defaults::http_server_port);
|
||||||
prefs->GetBool(prefs::http_server_enabled.c_str(), true);
|
prefs->GetBool(prefs::http_server_enabled.c_str(), true);
|
||||||
prefs->GetString(key::password.c_str(), nullptr, 0, defaults::password.c_str());
|
prefs->GetString(key::password.c_str(), nullptr, 0, defaults::password.c_str());
|
||||||
prefs->GetInt(prefs::http_server_transcoder_cache_count.c_str(), defaults::http_server_transcoder_cache_count);
|
prefs->GetInt(prefs::transcoder_cache_count.c_str(), defaults::transcoder_cache_count);
|
||||||
prefs->GetBool(prefs::http_server_transcoder_synchronous.c_str(), defaults::http_server_transcoder_synchronous);
|
prefs->GetBool(prefs::transcoder_synchronous.c_str(), defaults::transcoder_synchronous);
|
||||||
prefs->GetBool(prefs::http_server_transcoder_synchronous_fallback.c_str(), defaults::http_server_transcoder_synchronous_fallback);
|
prefs->GetBool(prefs::transcoder_synchronous_fallback.c_str(), defaults::transcoder_synchronous_fallback);
|
||||||
prefs->Save();
|
prefs->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include <core/debug.h>
|
#include <core/debug.h>
|
||||||
|
|
||||||
static const std::string TAG = "LocalLibrary";
|
static const std::string TAG = "LocalLibrary";
|
||||||
|
static bool scheduleSyncDueToDbUpgrade = false;
|
||||||
|
|
||||||
using namespace musik::core;
|
using namespace musik::core;
|
||||||
using namespace musik::core::library;
|
using namespace musik::core::library;
|
||||||
@ -90,6 +91,10 @@ LocalLibrary::LocalLibrary(std::string name,int id)
|
|||||||
this->GetLibraryDirectory(),
|
this->GetLibraryDirectory(),
|
||||||
this->GetDatabaseFilename());
|
this->GetDatabaseFilename());
|
||||||
|
|
||||||
|
if (scheduleSyncDueToDbUpgrade) {
|
||||||
|
this->indexer->Schedule(IIndexer::SyncType::Local);
|
||||||
|
}
|
||||||
|
|
||||||
this->thread = new std::thread(std::bind(&LocalLibrary::ThreadProc, this));
|
this->thread = new std::thread(std::bind(&LocalLibrary::ThreadProc, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,6 +295,8 @@ static void upgradeV2ToV3(db::Connection& db) {
|
|||||||
"name TEXT default '',"
|
"name TEXT default '',"
|
||||||
"thumbnail_id INTEGER default 0,"
|
"thumbnail_id INTEGER default 0,"
|
||||||
"sort_order INTEGER DEFAULT 0)");
|
"sort_order INTEGER DEFAULT 0)");
|
||||||
|
|
||||||
|
scheduleSyncDueToDbUpgrade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setVersion(db::Connection& db, int version) {
|
static void setVersion(db::Connection& db, int version) {
|
||||||
|
@ -59,6 +59,7 @@ public class MainActivity extends WebSocketActivityBase {
|
|||||||
private TextView title, artist, album, playPause, volume;
|
private TextView title, artist, album, playPause, volume;
|
||||||
private TextView titleWithArt, artistAndAlbumWithArt, volumeWithArt;
|
private TextView titleWithArt, artistAndAlbumWithArt, volumeWithArt;
|
||||||
private TextView notPlayingOrDisconnected;
|
private TextView notPlayingOrDisconnected;
|
||||||
|
private View buffering, bufferingWithArt;
|
||||||
private View connected;
|
private View connected;
|
||||||
private CheckBox shuffleCb, muteCb, repeatCb;
|
private CheckBox shuffleCb, muteCb, repeatCb;
|
||||||
private View disconnectedOverlay;
|
private View disconnectedOverlay;
|
||||||
@ -182,10 +183,12 @@ public class MainActivity extends WebSocketActivityBase {
|
|||||||
this.artist = (TextView) findViewById(R.id.track_artist);
|
this.artist = (TextView) findViewById(R.id.track_artist);
|
||||||
this.album = (TextView) findViewById(R.id.track_album);
|
this.album = (TextView) findViewById(R.id.track_album);
|
||||||
this.volume = (TextView) findViewById(R.id.volume);
|
this.volume = (TextView) findViewById(R.id.volume);
|
||||||
|
this.buffering = findViewById(R.id.buffering);
|
||||||
|
|
||||||
this.titleWithArt = (TextView) findViewById(R.id.with_art_track_title);
|
this.titleWithArt = (TextView) findViewById(R.id.with_art_track_title);
|
||||||
this.artistAndAlbumWithArt = (TextView) findViewById(R.id.with_art_artist_and_album);
|
this.artistAndAlbumWithArt = (TextView) findViewById(R.id.with_art_artist_and_album);
|
||||||
this.volumeWithArt = (TextView) findViewById(R.id.with_art_volume);
|
this.volumeWithArt = (TextView) findViewById(R.id.with_art_volume);
|
||||||
|
this.bufferingWithArt = findViewById(R.id.with_art_buffering);
|
||||||
|
|
||||||
this.playPause = (TextView) findViewById(R.id.button_play_pause);
|
this.playPause = (TextView) findViewById(R.id.button_play_pause);
|
||||||
this.shuffleCb = (CheckBox) findViewById(R.id.check_shuffle);
|
this.shuffleCb = (CheckBox) findViewById(R.id.check_shuffle);
|
||||||
@ -263,8 +266,13 @@ public class MainActivity extends WebSocketActivityBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void rebindAlbumArtistWithArtTextView() {
|
private void rebindAlbumArtistWithArtTextView() {
|
||||||
final String artist = playback.getTrackString(Metadata.Track.ARTIST, getString(R.string.unknown_artist));
|
final boolean buffering = playback.getPlaybackState() == PlaybackState.Buffering;
|
||||||
final String album = playback.getTrackString(Metadata.Track.ALBUM, getString(R.string.unknown_album));
|
|
||||||
|
final String artist = playback.getTrackString(
|
||||||
|
Metadata.Track.ARTIST, getString(buffering ? R.string.buffering : R.string.unknown_artist));
|
||||||
|
|
||||||
|
final String album = playback.getTrackString(
|
||||||
|
Metadata.Track.ALBUM, getString(buffering ? R.string.buffering : R.string.unknown_album));
|
||||||
|
|
||||||
final ForegroundColorSpan albumColor =
|
final ForegroundColorSpan albumColor =
|
||||||
new ForegroundColorSpan(getResources().getColor(R.color.theme_orange));
|
new ForegroundColorSpan(getResources().getColor(R.color.theme_orange));
|
||||||
@ -328,6 +336,8 @@ public class MainActivity extends WebSocketActivityBase {
|
|||||||
final boolean stopped = (playback.getPlaybackState() == PlaybackState.Stopped);
|
final boolean stopped = (playback.getPlaybackState() == PlaybackState.Stopped);
|
||||||
notPlayingOrDisconnected.setVisibility(stopped ? View.VISIBLE : View.GONE);
|
notPlayingOrDisconnected.setVisibility(stopped ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
boolean buffering = playback.getPlaybackState() == PlaybackState.Buffering;
|
||||||
|
|
||||||
final boolean stateIsValidForArtwork = !stopped && connected && playback.getQueueCount() > 0;
|
final boolean stateIsValidForArtwork = !stopped && connected && playback.getQueueCount() > 0;
|
||||||
|
|
||||||
this.connected.setVisibility((connected && stopped) ? View.VISIBLE : View.GONE);
|
this.connected.setVisibility((connected && stopped) ? View.VISIBLE : View.GONE);
|
||||||
@ -350,15 +360,18 @@ public class MainActivity extends WebSocketActivityBase {
|
|||||||
final String title = playback.getTrackString(Metadata.Track.TITLE, "");
|
final String title = playback.getTrackString(Metadata.Track.TITLE, "");
|
||||||
final String volume = getString(R.string.status_volume, Math.round(playback.getVolume() * 100));
|
final String volume = getString(R.string.status_volume, Math.round(playback.getVolume() * 100));
|
||||||
|
|
||||||
this.title.setText(Strings.empty(title) ? getString(R.string.unknown_title) : title);
|
this.title.setText(Strings.empty(title) ? getString(buffering ? R.string.buffering : R.string.unknown_title) : title);
|
||||||
this.artist.setText(Strings.empty(artist) ? getString(R.string.unknown_artist) : artist);
|
this.artist.setText(Strings.empty(artist) ? getString(buffering ? R.string.buffering : R.string.unknown_artist) : artist);
|
||||||
this.album.setText(Strings.empty(album) ? getString(R.string.unknown_album) : album);
|
this.album.setText(Strings.empty(album) ? getString(buffering ? R.string.buffering : R.string.unknown_album) : album);
|
||||||
this.volume.setText(volume);
|
this.volume.setText(volume);
|
||||||
|
|
||||||
this.rebindAlbumArtistWithArtTextView();
|
this.rebindAlbumArtistWithArtTextView();
|
||||||
this.titleWithArt.setText(Strings.empty(title) ? getString(R.string.unknown_title) : title);
|
this.titleWithArt.setText(Strings.empty(title) ? getString(buffering ? R.string.buffering : R.string.unknown_title) : title);
|
||||||
this.volumeWithArt.setText(volume);
|
this.volumeWithArt.setText(volume);
|
||||||
|
|
||||||
|
this.buffering.setVisibility(buffering ? View.VISIBLE : View.GONE);
|
||||||
|
this.bufferingWithArt.setVisibility(buffering ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
final RepeatMode repeatMode = playback.getRepeatMode();
|
final RepeatMode repeatMode = playback.getRepeatMode();
|
||||||
final boolean repeatChecked = (repeatMode != RepeatMode.None);
|
final boolean repeatChecked = (repeatMode != RepeatMode.None);
|
||||||
repeatCb.setText(REPEAT_TO_STRING_ID.get(repeatMode));
|
repeatCb.setText(REPEAT_TO_STRING_ID.get(repeatMode));
|
||||||
@ -381,7 +394,6 @@ public class MainActivity extends WebSocketActivityBase {
|
|||||||
this.albumArtModel.destroy();
|
this.albumArtModel.destroy();
|
||||||
this.albumArtModel = new AlbumArtModel(title, artist, album, albumArtRetrieved);
|
this.albumArtModel = new AlbumArtModel(title, artist, album, albumArtRetrieved);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAlbumArt();
|
updateAlbumArt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -764,6 +764,7 @@ public class StreamingPlaybackService implements PlaybackService {
|
|||||||
.doOnComplete(() -> {
|
.doOnComplete(() -> {
|
||||||
if (StreamingPlaybackService.this.params == params) {
|
if (StreamingPlaybackService.this.params == params) {
|
||||||
StreamingPlaybackService.this.context = context;
|
StreamingPlaybackService.this.context = context;
|
||||||
|
notifyEventListeners();
|
||||||
onPlayQueueLoaded();
|
onPlayQueueLoaded();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -24,7 +24,7 @@ public class TransportFragment extends Fragment {
|
|||||||
return new TransportFragment();
|
return new TransportFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
private View rootView;
|
private View rootView, buffering;
|
||||||
private TextView title, playPause;
|
private TextView title, playPause;
|
||||||
private PlaybackService playback;
|
private PlaybackService playback;
|
||||||
private OnModelChangedListener modelChangedListener;
|
private OnModelChangedListener modelChangedListener;
|
||||||
@ -60,6 +60,7 @@ public class TransportFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
rebindUi();
|
||||||
this.playback.connect(this.playbackListener);
|
this.playback.connect(this.playbackListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +74,10 @@ public class TransportFragment extends Fragment {
|
|||||||
|
|
||||||
private void bindEventHandlers() {
|
private void bindEventHandlers() {
|
||||||
this.title = (TextView) this.rootView.findViewById(R.id.track_title);
|
this.title = (TextView) this.rootView.findViewById(R.id.track_title);
|
||||||
|
this.buffering = this.rootView.findViewById(R.id.buffering);
|
||||||
|
|
||||||
this.title.setOnClickListener((View view) -> {
|
final View titleBar = this.rootView.findViewById(R.id.title_bar);
|
||||||
|
titleBar.setOnClickListener((View view) -> {
|
||||||
if (playback.getPlaybackState() != PlaybackState.Stopped) {
|
if (playback.getPlaybackState() != PlaybackState.Stopped) {
|
||||||
final Intent intent = PlayQueueActivity
|
final Intent intent = PlayQueueActivity
|
||||||
.getStartIntent(getActivity(), playback.getQueuePosition())
|
.getStartIntent(getActivity(), playback.getQueuePosition())
|
||||||
@ -109,7 +112,10 @@ public class TransportFragment extends Fragment {
|
|||||||
PlaybackState state = playback.getPlaybackState();
|
PlaybackState state = playback.getPlaybackState();
|
||||||
|
|
||||||
final boolean playing = (state == PlaybackState.Playing);
|
final boolean playing = (state == PlaybackState.Playing);
|
||||||
|
final boolean buffering = (state == PlaybackState.Buffering);
|
||||||
|
|
||||||
this.playPause.setText(playing ? R.string.button_pause : R.string.button_play);
|
this.playPause.setText(playing ? R.string.button_pause : R.string.button_play);
|
||||||
|
this.buffering.setVisibility(buffering ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
if (state == PlaybackState.Stopped) {
|
if (state == PlaybackState.Stopped) {
|
||||||
title.setTextColor(getActivity().getResources().getColor(R.color.theme_disabled_foreground));
|
title.setTextColor(getActivity().getResources().getColor(R.color.theme_disabled_foreground));
|
||||||
@ -117,7 +123,9 @@ public class TransportFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
title.setTextColor(getActivity().getResources().getColor(R.color.theme_green));
|
title.setTextColor(getActivity().getResources().getColor(R.color.theme_green));
|
||||||
title.setText(playback.getTrackString(Metadata.Track.TITLE, "(unknown title)"));
|
|
||||||
|
final String defaultValue = getString(buffering ? R.string.buffering : R.string.unknown_title);
|
||||||
|
title.setText(playback.getTrackString(Metadata.Track.TITLE, defaultValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,14 @@
|
|||||||
android:paddingTop="2dp"
|
android:paddingTop="2dp"
|
||||||
android:paddingBottom="2dp">
|
android:paddingBottom="2dp">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/with_art_buffering"
|
||||||
|
style="?android:attr/progressBarStyleSmall"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="@style/LightDropShadow"
|
style="@style/LightDropShadow"
|
||||||
android:id="@+id/with_art_track_title"
|
android:id="@+id/with_art_track_title"
|
||||||
@ -103,6 +111,14 @@
|
|||||||
android:paddingTop="6dp"
|
android:paddingTop="6dp"
|
||||||
android:paddingBottom="6dp">
|
android:paddingBottom="6dp">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/buffering"
|
||||||
|
style="?android:attr/progressBarStyleSmall"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/track_title"
|
android:id="@+id/track_title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -51,15 +51,42 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="2dp"/>
|
android:layout_height="2dp"/>
|
||||||
|
|
||||||
<TextView
|
<FrameLayout
|
||||||
style="@style/TransportPlaying"
|
android:id="@+id/title_bar"
|
||||||
android:id="@+id/track_title"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:background="@drawable/category_button"
|
||||||
android:maxLines="1"
|
android:paddingLeft="4dp"
|
||||||
android:ellipsize="end"
|
android:paddingRight="4dp">
|
||||||
android:textColor="@color/theme_disabled_foreground"
|
|
||||||
android:text="@string/transport_not_playing"/>
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/buffering"
|
||||||
|
style="?android:attr/progressBarStyleSmall"
|
||||||
|
android:paddingRight="6dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TransportPlaying"
|
||||||
|
android:id="@+id/track_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textColor="@color/theme_disabled_foreground"
|
||||||
|
android:text="@string/transport_not_playing"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -68,4 +68,5 @@
|
|||||||
<string name="unknown_artist">[unknown artist]</string>
|
<string name="unknown_artist">[unknown artist]</string>
|
||||||
<string name="unknown_album">[unknown album]</string>
|
<string name="unknown_album">[unknown album]</string>
|
||||||
<string name="unknown_title">[unknown title]</string>
|
<string name="unknown_title">[unknown title]</string>
|
||||||
|
<string name="buffering">buffering</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -18,13 +18,10 @@
|
|||||||
|
|
||||||
<style name="TransportPlaying">
|
<style name="TransportPlaying">
|
||||||
<item name="android:layout_margin">0dp</item>
|
<item name="android:layout_margin">0dp</item>
|
||||||
<item name="android:paddingLeft">4dp</item>
|
|
||||||
<item name="android:paddingRight">4dp</item>
|
|
||||||
<item name="android:paddingTop">6dp</item>
|
<item name="android:paddingTop">6dp</item>
|
||||||
<item name="android:paddingBottom">6dp</item>
|
<item name="android:paddingBottom">6dp</item>
|
||||||
<item name="android:gravity">center</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:textColor">@color/theme_foreground</item>
|
<item name="android:textColor">@color/theme_foreground</item>
|
||||||
<item name="android:background">@drawable/category_button</item>
|
|
||||||
<item name="android:clickable">true</item>
|
<item name="android:clickable">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user