Add a "Cover" replicant (for album covers, etc)

This replicant will search for an image file related to the current
playing item, and will display it. Otherwise, it's transparent.
This commit is contained in:
Jaidyn Ann 2022-05-01 13:20:18 -05:00
parent 78dec2ec7e
commit a4c1635962
6 changed files with 192 additions and 3 deletions

View File

@ -33,6 +33,7 @@ APP_MIME_SIG = application/x-vnd.mediamonitor
# Also note that spaces in folder names do not work well with this Makefile.
SRCS = src/App.cpp \
src/MainWindow.cpp \
src/CoverView.cpp \
src/LyricsView.cpp \
src/Song.cpp
@ -60,7 +61,7 @@ RSRCS =
# - if your library does not follow the standard library naming scheme,
# you need to specify the path to the library and it's name.
# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a")
LIBS = be $(STDCPPLIBS)
LIBS = be translation $(STDCPPLIBS)
# Specify additional paths to directories following the standard libXXX.so
# or libXXX.a naming scheme. You can specify full paths or paths relative

100
src/CoverView.cpp Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "CoverView.h"
#include <Bitmap.h>
#include <Dragger.h>
#include <Messenger.h>
#include "Song.h"
CoverView::CoverView(BRect frame)
:
BView(frame, "Cover", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_PULSE_NEEDED)
{
BRect dragRect(0, 0, 10, frame.Height());
fDragger = new BDragger(dragRect, this,
B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW);
fDragger->SetViewColor(B_TRANSPARENT_COLOR);
AddChild(fDragger);
fCover = NULL;
SetViewColor(B_TRANSPARENT_COLOR);
Pulse();
}
CoverView::CoverView(BMessage* data)
:
BView(data)
{
fCover = NULL;
SetViewColor(B_TRANSPARENT_COLOR);
Pulse();
}
status_t
CoverView::Archive(BMessage* data, bool deep) const
{
status_t status = BView::Archive(data, deep);
data->AddString("class", "CoverView");
data->AddString("add_on", "application/x-vnd.mediamonitor");
return status;
}
CoverView*
CoverView::Instantiate(BMessage* data)
{
if (!validate_instantiation(data, "CoverView"))
return NULL;
return new CoverView(data);
}
void
CoverView::Pulse()
{
BString path = _GetCurrentPath();
if (path.IsEmpty() == false && path != fCurrentPath) {
fCurrentPath = path;
Song song(path.String());
delete fCover;
fCover = song.Cover();
Invalidate();
} else if (path.IsEmpty() == true && path != fCurrentPath) {
fCurrentPath = path;
delete fCover;
Invalidate();
}
}
void
CoverView::Draw(BRect updateRect)
{
BView::Draw(updateRect);
if (fCover != NULL)
DrawBitmap(fCover, Bounds());
}
BString
CoverView::_GetCurrentPath()
{
BMessage message, reply;
message.what = B_GET_PROPERTY;
message.AddSpecifier("URI");
message.AddSpecifier("Window", 0);
BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(&message, &reply);
BString result;
reply.FindString("result", &result);
return result.ReplaceAll("file://", "");
}

35
src/CoverView.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef COVERVIEW_H
#define COVERVIEW_H
#include <View.h>
class BDragger;
class CoverView : public BView {
public:
CoverView(BRect frame);
CoverView(BMessage* archive);
virtual status_t Archive(BMessage* data, bool deep = true) const;
static CoverView* Instantiate(BMessage* data);
virtual void Pulse();
virtual void Draw(BRect updateRect);
private:
void _Init(BRect frame);
BString _GetCurrentPath();
BString _GetCoverPath();
BDragger* fDragger;
BBitmap* fCover;
BString fCurrentPath;
};
#endif // COVERVIEW_H

View File

@ -8,6 +8,7 @@
#include <LayoutBuilder.h>
#include <TabView.h>
#include "CoverView.h"
#include "LyricsView.h"
@ -27,6 +28,7 @@ MainWindow::_InitInterface()
{
BTabView* tabView = new BTabView("appletTabView");
tabView->AddTab(new LyricsView(BRect(BPoint(0,0), BSize(300.0, 200.0))));
tabView->AddTab(new CoverView(BRect(BPoint(0,0), BSize(300.0, 200.0))));
BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
.Add(tabView)

View File

@ -10,6 +10,7 @@
#include <Directory.h>
#include <File.h>
#include <String.h>
#include <TranslationUtils.h>
Song::Song(const char* path)
@ -36,6 +37,13 @@ Song::Lyrics(BString* buffer)
}
BBitmap*
Song::Cover()
{
return BTranslationUtils::GetBitmapFile(_CoverPath().Path());
}
// Our song's leaf, sans file extension
const char*
Song::_FileLeaf()
@ -49,6 +57,38 @@ Song::_FileLeaf()
// Search for any text-file with the same leaf of the song
BPath
Song::_LyricsPath()
{
return _SimilarFileOfType("text/");
}
// Search for any image-file in the same directory
BPath
Song::_CoverPath()
{
BPath path = _SimilarFileOfType("image/");
if (path.InitCheck() != B_OK)
path = _AnyFileOfType("image/");
return path;
}
BPath
Song::_SimilarFileOfType(const char* mimeRoot)
{
return _FindFile(mimeRoot, true);
}
BPath
Song::_AnyFileOfType(const char* mimeRoot)
{
return _FindFile(mimeRoot, false);
}
BPath
Song::_FindFile(const char* mimeRoot, bool byName)
{
BString leaf(_FileLeaf());
BPath parentPath;
@ -64,10 +104,14 @@ Song::_LyricsPath()
entry.GetPath(&entryPath);
BString entryLeaf(entryPath.Leaf());
if (entryLeaf != leaf && entryLeaf.FindFirst(leaf) >= 0) {
bool nameAgrees = (entryLeaf != leaf && entryLeaf.FindFirst(leaf) >= 0);
if (byName == false || nameAgrees == true) {
BString mimeType;
node.SetTo(&entry);
if (node.ReadAttrString("BEOS:TYPE", &mimeType) == B_OK && mimeType.StartsWith("text/"))
if (mimeRoot == NULL ||
(node.ReadAttrString("BEOS:TYPE", &mimeType) == B_OK
&& mimeType.StartsWith(mimeRoot)))
return entryPath;
}
}

View File

@ -7,15 +7,22 @@
#include <Path.h>
class BBitmap;
class Song {
public:
Song(const char* path);
status_t Lyrics(BString* buffer);
BBitmap* Cover();
private:
const char* _FileLeaf();
BPath _LyricsPath();
BPath _CoverPath();
BPath _SimilarFileOfType(const char* mimeRoot);
BPath _AnyFileOfType(const char* mimeRoot);
BPath _FindFile(const char* mimeRoot, bool byName);
BPath fPath;
};