Add "directory" as a browse category type.

This commit is contained in:
casey langen 2020-03-31 17:49:11 -07:00
parent 6ff6bce076
commit 43a8ca1d8d
8 changed files with 155 additions and 24 deletions

View File

@ -30,6 +30,7 @@ set (CUBE_SRCS
./app/util/ConsoleLogger.cpp
./app/util/GlobalHotkeys.cpp
./app/util/Hotkeys.cpp
./app/util/MagicConstants.cpp
./app/util/PreferenceKeys.cpp
./app/util/Playback.cpp
./app/util/Rating.cpp

View File

@ -48,6 +48,7 @@
#include <app/util/Hotkeys.h>
#include <app/util/Messages.h>
#include <app/util/PreferenceKeys.h>
#include <app/util/MagicConstants.h>
#include <core/support/Playback.h>
#include "LibraryLayout.h"
@ -392,6 +393,14 @@ void LibraryLayout::ProcessMessage(musik::core::runtime::IMessage &message) {
LayoutBase::ProcessMessage(message);
}
void LibraryLayout::ShowDirectoryChooser() {
BrowseOverlays::ShowDirectoryChooser(
this->library,
[this](std::string directory) {
this->ShowDirectories(directory);
});
}
bool LibraryLayout::KeyPress(const std::string& key) {
if (this->visibleLayout == this->browseLayout ||
this->visibleLayout == this->directoryLayout)
@ -419,8 +428,13 @@ bool LibraryLayout::KeyPress(const std::string& key) {
else if (Hotkeys::Is(Hotkeys::NavigateLibraryBrowseChooseCategory, key)) {
BrowseOverlays::ShowCategoryChooser(
this->library,
[this](std::string category) {
this->ShowBrowse(category);
[this](std::string category, std::string type) {
if (type == MagicConstants::DirectoryCategoryType) {
this->ShowDirectoryChooser();
}
else {
this->ShowBrowse(category);
}
});
return true;
}
@ -443,11 +457,7 @@ bool LibraryLayout::KeyPress(const std::string& key) {
return true;
}
else if (Hotkeys::Is(Hotkeys::NavigateLibraryBrowseDirectories, key)) {
BrowseOverlays::ShowDirectoryChooser(
this->library,
[this](std::string directory) {
this->ShowDirectories(directory);
});
this->ShowDirectoryChooser();
return true;
}
else if (this->GetFocus() == this->transportView && Hotkeys::Is(Hotkeys::Up, key)) {

View File

@ -96,6 +96,7 @@ namespace musik {
void ShowBrowse(const std::string& category = "");
void ShowCategorySearch();
void ShowTrackSearch();
void ShowDirectoryChooser();
void ShowDirectories(const std::string& directory);
void ChangeMainLayout(std::shared_ptr<cursespp::LayoutBase> newLayout);

View File

@ -35,7 +35,9 @@
#include <stdafx.h>
#include "BrowseOverlays.h"
#include <app/util/MagicConstants.h>
#include <core/library/query/local/AllCategoriesQuery.h>
#include <core/i18n/Locale.h>
#include <cursespp/SimpleScrollAdapter.h>
#include <cursespp/ListOverlay.h>
#include <cursespp/DialogOverlay.h>
@ -48,7 +50,7 @@ using namespace musik::core;
using namespace musik::core::db;
using namespace musik::core::db::local;
static const std::set<std::string> BLACKLIST = { "bitrate", "channels", "lyrics", "path_id" };
static const std::set<std::string> BLACKLIST = { "bitrate", "channels", "lyrics", "path_id", "directory" };
static std::string lastSelectedCategory, lastSelectedDirectory;
static void showNoPathsError() {
@ -64,7 +66,7 @@ static void showNoPathsError() {
void BrowseOverlays::ShowCategoryChooser(
musik::core::ILibraryPtr library,
std::function<void(std::string)> callback)
std::function<void(std::string, std::string)> callback)
{
using Adapter = cursespp::SimpleScrollAdapter;
using ListOverlay = cursespp::ListOverlay;
@ -77,16 +79,29 @@ void BrowseOverlays::ShowCategoryChooser(
adapter->SetSelectable(true);
size_t index = 0;
auto filtered = query->GetResult()->Filter([&index, adapter](const Value& value) -> bool {
auto result = query->GetResult();
auto filtered = result->Filter([&index, adapter](const Value& value) -> bool {
auto str = value->ToString();
if (BLACKLIST.find(str) == BLACKLIST.end()) {
adapter->AddEntry(str);
if (lastSelectedCategory == str) {
index = adapter->GetEntryCount() - 1;
}
return true;
return BLACKLIST.find(str) == BLACKLIST.end();
});
filtered->Add(std::make_shared<SdkValue>(
_TSTR("browse_title_directory"),
-1LL,
MagicConstants::DirectoryCategoryType));
filtered->Sort([](const auto a, const auto b) -> bool {
return a->ToString() < b->ToString();
});
filtered->Each([&index, adapter](const Value& value) {
auto str = value->ToString();
adapter->AddEntry(str);
if (lastSelectedCategory == str) {
index = adapter->GetEntryCount() - 1;
}
return false;
});
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
@ -98,8 +113,9 @@ void BrowseOverlays::ShowCategoryChooser(
.SetItemSelectedCallback(
[callback, filtered]
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
lastSelectedCategory = filtered->At(index)->ToString();
callback(lastSelectedCategory);
auto selected = filtered->At(index);
lastSelectedCategory = selected->ToString();
callback(lastSelectedCategory, selected->GetType());
});
cursespp::App::Overlays().Push(dialog);

View File

@ -43,7 +43,7 @@ namespace musik {
public:
static void ShowCategoryChooser(
musik::core::ILibraryPtr library,
std::function<void(std::string)> callback);
std::function<void(std::string, std::string)> callback);
static void ShowDirectoryChooser(
musik::core::ILibraryPtr library,

View File

@ -50,6 +50,7 @@
#include <core/runtime/Message.h>
#include <app/util/Messages.h>
#include <app/util/MagicConstants.h>
#include <cursespp/App.h>
#include <cursespp/SimpleScrollAdapter.h>
@ -77,8 +78,6 @@ static size_t lastCategoryOverlayIndex = 0;
static int64_t lastPlaylistId = -1;
static milliseconds lastOperationExpiry;
static std::string kDirectoryFieldColumn = "__directoryCategory__";
using Adapter = cursespp::SimpleScrollAdapter;
static inline milliseconds now() {
@ -132,7 +131,7 @@ static std::shared_ptr<TrackList> queryTracksByCategory(
special `fieldColumn` called `kDirectoryFieldColumn`. If we detect this case
we'll run a special query for directory path matching */
std::shared_ptr<TrackListQueryBase> query;
if (categoryType == kDirectoryFieldColumn) {
if (categoryType == MagicConstants::DirectoryCategoryType) {
query = std::make_shared<DirectoryTrackListQuery>(library, categoryValue);
}
else {
@ -558,7 +557,13 @@ void PlayQueueOverlays::ShowAddDirectoryOverlay(
musik::core::ILibraryPtr library,
const std::string& directory)
{
ShowAddCategoryOverlay(messageQueue, playback, library, kDirectoryFieldColumn, directory, -1LL);
ShowAddCategoryOverlay(
messageQueue,
playback,
library,
MagicConstants::DirectoryCategoryType,
directory,
-1LL);
}
void PlayQueueOverlays::ShowAlbumDividerOverlay(

View File

@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////
#include "MagicConstants.h"
using namespace musik::cube;
namespace musik { namespace cube {
const std::string MagicConstants::DirectoryCategoryType = "__DirectoryCategoryType__";
} }

View File

@ -0,0 +1,55 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
namespace musik { namespace cube {
/**
* MagicConstants is used to house shared constants that are typically used as markers
* to glue together otherwise disjoint features that may make sense to interoperate in
* and integrate in the UI layer. One example of this: present directory browsing as
* a category type, even though it's a category in the database.
*
* We should strive for magic constants to be empty, but in some cases doing serious
* refactors of subsystems is prohibitively expensive and would not gain much.
*/
struct MagicConstants {
static const std::string DirectoryCategoryType;
private: MagicConstants(){}
};
} }