oh, naive i am. there will be several more things needed to be able to release this...
This commit is contained in:
parent
4e86256f1b
commit
58584e8ab2
|
|
@ -0,0 +1,21 @@
|
|||
# Privacy Policy
|
||||
|
||||
**Yr Crystals** does not collect, store, or transmit any personal data.
|
||||
|
||||
## Device Permissions
|
||||
|
||||
The app may request access to the following device features solely for local, on-device functionality:
|
||||
|
||||
- **Music Library** — To play audio tracks from your library.
|
||||
|
||||
No data from these sources is recorded, uploaded, or shared. All processing happens entirely on your device.
|
||||
|
||||
## Third-Party Services
|
||||
|
||||
Yr Crystals does not use analytics, advertising, tracking, or any third-party services.
|
||||
|
||||
## Contact
|
||||
|
||||
If you have questions about this policy, contact: **[your email]**
|
||||
|
||||
*Last updated: March 1, 2026*
|
||||
|
|
@ -39,14 +39,8 @@
|
|||
</array>
|
||||
|
||||
<!-- Permissions -->
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>This app requires audio access to visualize music.</string>
|
||||
<key>NSAppleMusicUsageDescription</key>
|
||||
<string>This app requires access to your music library to play tracks.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>This app requires access to the photo library to load album art.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app requires camera access for visualizer input.</string>
|
||||
<string>Yr Crystals needs access to your music library to play tracks.</string>
|
||||
|
||||
<!-- File Access -->
|
||||
<key>UIFileSharingEnabled</key>
|
||||
|
|
|
|||
|
|
@ -463,11 +463,11 @@ OverlayWidget::OverlayWidget(QWidget *content, QWidget *parent)
|
|||
hide();
|
||||
}
|
||||
|
||||
void OverlayWidget::showEvent(QShowEvent *event) {
|
||||
QWidget::showEvent(event);
|
||||
void OverlayWidget::setVisible(bool visible) {
|
||||
if (visible && !isVisible()) {
|
||||
if constexpr (Theme::FrostedGlass) {
|
||||
if (auto *w = window()) {
|
||||
QPixmap shot = w->grab();
|
||||
if (auto *p = parentWidget()) {
|
||||
QPixmap shot = p->grab();
|
||||
int sw = shot.width() / 10;
|
||||
int sh = shot.height() / 10;
|
||||
m_blurredBg = shot.scaled(sw, sh, Qt::IgnoreAspectRatio,
|
||||
|
|
@ -477,6 +477,8 @@ void OverlayWidget::showEvent(QShowEvent *event) {
|
|||
}
|
||||
}
|
||||
}
|
||||
QWidget::setVisible(visible);
|
||||
}
|
||||
|
||||
void OverlayWidget::mousePressEvent(QMouseEvent *event) {
|
||||
if (!m_content->geometry().contains(event->pos()))
|
||||
|
|
|
|||
|
|
@ -128,9 +128,9 @@ class OverlayWidget : public QWidget {
|
|||
Q_OBJECT
|
||||
public:
|
||||
OverlayWidget(QWidget *content, QWidget *parent = nullptr);
|
||||
void setVisible(bool visible) override;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "Theme.h"
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QVBoxLayout>
|
||||
#include <cmath>
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ PlaybackWidget::PlaybackWidget(QWidget *parent) : QWidget(parent) {
|
|||
.arg(Theme::rgba(Theme::Colors::PlaybackSurface),
|
||||
Theme::hex(Theme::Colors::BorderSubtle)));
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(10, 5, 10, 10);
|
||||
mainLayout->setContentsMargins(10, 5, 10, 2);
|
||||
|
||||
m_seekSlider = new TouchSlider(this);
|
||||
m_seekSlider->setRange(0, 1000);
|
||||
|
|
@ -42,12 +43,11 @@ PlaybackWidget::PlaybackWidget(QWidget *parent) : QWidget(parent) {
|
|||
|
||||
QString auxStyle = QString(
|
||||
"QPushButton { background: transparent; color: %1; font-size: %2px; "
|
||||
"border: none; padding: 10px;%3 } "
|
||||
"QPushButton:pressed { color: %4; }")
|
||||
"border: none; padding: 16px 20px; min-width: 48px; min-height: 48px; } "
|
||||
"QPushButton:pressed { color: %3; }")
|
||||
.arg(Theme::hex(Theme::Colors::TextSecondary))
|
||||
.arg(Theme::Dims::BtnFontSize)
|
||||
.arg(minSizeRule,
|
||||
Theme::hex(Theme::Colors::TextPrimary));
|
||||
.arg(Theme::hex(Theme::Colors::TextPrimary));
|
||||
|
||||
QPushButton *btnPrev = new QPushButton("<<", this);
|
||||
btnPrev->setStyleSheet(btnStyle);
|
||||
|
|
@ -62,23 +62,23 @@ PlaybackWidget::PlaybackWidget(QWidget *parent) : QWidget(parent) {
|
|||
btnNext->setStyleSheet(btnStyle);
|
||||
connect(btnNext, &QPushButton::clicked, this, &PlaybackWidget::nextClicked);
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
QPushButton *btnSettings = new QPushButton("...", this);
|
||||
#ifdef IS_MOBILE
|
||||
rowLayout->addStretch();
|
||||
rowLayout->addWidget(btnPrev);
|
||||
rowLayout->addSpacing(10);
|
||||
rowLayout->addWidget(m_btnPlay);
|
||||
rowLayout->addSpacing(10);
|
||||
rowLayout->addWidget(btnNext);
|
||||
rowLayout->addStretch();
|
||||
#else
|
||||
QPushButton *btnSettings = new QPushButton("⚙", this);
|
||||
#endif
|
||||
btnSettings->setStyleSheet(auxStyle);
|
||||
connect(btnSettings, &QPushButton::clicked, this,
|
||||
&PlaybackWidget::settingsClicked);
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
QPushButton *btnHome = new QPushButton("<", this);
|
||||
#else
|
||||
QPushButton *btnHome = new QPushButton("⌂", this);
|
||||
#endif
|
||||
btnHome->setStyleSheet(auxStyle);
|
||||
connect(btnHome, &QPushButton::clicked, this, &PlaybackWidget::homeClicked);
|
||||
|
||||
rowLayout->addWidget(btnHome);
|
||||
rowLayout->addStretch();
|
||||
rowLayout->addWidget(btnPrev);
|
||||
|
|
@ -88,6 +88,7 @@ PlaybackWidget::PlaybackWidget(QWidget *parent) : QWidget(parent) {
|
|||
rowLayout->addWidget(btnNext);
|
||||
rowLayout->addStretch();
|
||||
rowLayout->addWidget(btnSettings);
|
||||
#endif
|
||||
|
||||
mainLayout->addLayout(rowLayout);
|
||||
}
|
||||
|
|
@ -401,16 +402,70 @@ void SettingsWidget::onSmoothingChanged(int val) {
|
|||
emitParams();
|
||||
}
|
||||
|
||||
// --- SideButton ---
|
||||
|
||||
SideButton::SideButton(Icon icon, QWidget *parent)
|
||||
: QWidget(parent), m_icon(icon) {
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
}
|
||||
|
||||
void SideButton::paintEvent(QPaintEvent *) {
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int cx = width() / 2;
|
||||
int cy = height() / 2;
|
||||
float s = std::min(width(), height()) * 0.18f;
|
||||
|
||||
p.setPen(QPen(Theme::Colors::TextSecondary, s * 0.22f, Qt::SolidLine,
|
||||
Qt::RoundCap, Qt::RoundJoin));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
|
||||
if (m_icon == Home) {
|
||||
float gap = s * 0.35f;
|
||||
float barH = s * 0.9f;
|
||||
float barTop = cy;
|
||||
p.drawLine(QPointF(cx - gap, barTop), QPointF(cx - gap, barTop + barH));
|
||||
p.drawLine(QPointF(cx + gap, barTop), QPointF(cx + gap, barTop + barH));
|
||||
float peakY = cy - s * 0.5f;
|
||||
p.drawLine(QPointF(cx - s * 0.55f, cy + s * 0.1f), QPointF(cx, peakY));
|
||||
p.drawLine(QPointF(cx, peakY), QPointF(cx + s * 0.55f, cy + s * 0.1f));
|
||||
} else {
|
||||
int rays = 6;
|
||||
for (int i = 0; i < rays; i++) {
|
||||
float a = i * M_PI / rays;
|
||||
float dx = cos(a) * s * 0.7f;
|
||||
float dy = sin(a) * s * 0.7f;
|
||||
p.drawLine(QPointF(cx - dx, cy - dy), QPointF(cx + dx, cy + dy));
|
||||
}
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(Theme::Colors::TextSecondary);
|
||||
p.drawEllipse(QPointF(cx, cy), s * 0.25f, s * 0.25f);
|
||||
}
|
||||
}
|
||||
|
||||
void SideButton::mousePressEvent(QMouseEvent *) { emit clicked(); }
|
||||
|
||||
// --- PlayerPage ---
|
||||
|
||||
PlayerPage::PlayerPage(QWidget *parent) : QWidget(parent) {
|
||||
m_visualizer = new VisualizerWidget(this);
|
||||
m_playback = new PlaybackWidget(this);
|
||||
m_settings = new SettingsWidget();
|
||||
m_overlay = new OverlayWidget(m_settings, this);
|
||||
|
||||
#ifdef IS_MOBILE
|
||||
m_btnHome = new SideButton(SideButton::Home, this);
|
||||
connect(m_btnHome, &SideButton::clicked, this, &PlayerPage::homeClicked);
|
||||
|
||||
m_btnSettings = new SideButton(SideButton::Settings, this);
|
||||
connect(m_btnSettings, &SideButton::clicked, this, &PlayerPage::toggleOverlay);
|
||||
#else
|
||||
connect(m_playback, &PlaybackWidget::settingsClicked, this,
|
||||
&PlayerPage::toggleOverlay);
|
||||
connect(m_playback, &PlaybackWidget::homeClicked, this,
|
||||
&PlayerPage::homeClicked);
|
||||
#endif
|
||||
connect(m_settings, &SettingsWidget::closeClicked, this,
|
||||
&PlayerPage::closeOverlay);
|
||||
|
||||
|
|
@ -449,18 +504,30 @@ PlayerPage::PlayerPage(QWidget *parent) : QWidget(parent) {
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerPage::setFullScreen(bool fs) { m_playback->setVisible(!fs); }
|
||||
void PlayerPage::setFullScreen(bool fs) {
|
||||
m_playback->setVisible(!fs);
|
||||
if (m_btnHome) m_btnHome->setVisible(!fs);
|
||||
if (m_btnSettings) m_btnSettings->setVisible(!fs);
|
||||
}
|
||||
|
||||
void PlayerPage::toggleOverlay() {
|
||||
if (m_overlay->isVisible())
|
||||
if (m_overlay->isVisible()) {
|
||||
m_overlay->hide();
|
||||
else {
|
||||
if (m_btnHome) m_btnHome->show();
|
||||
if (m_btnSettings) m_btnSettings->show();
|
||||
} else {
|
||||
if (m_btnHome) m_btnHome->hide();
|
||||
if (m_btnSettings) m_btnSettings->hide();
|
||||
m_overlay->raise();
|
||||
m_overlay->show();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerPage::closeOverlay() { m_overlay->hide(); }
|
||||
void PlayerPage::closeOverlay() {
|
||||
m_overlay->hide();
|
||||
if (m_btnHome) m_btnHome->show();
|
||||
if (m_btnSettings) m_btnSettings->show();
|
||||
}
|
||||
|
||||
void PlayerPage::resizeEvent(QResizeEvent *event) {
|
||||
int w = event->size().width();
|
||||
|
|
@ -475,4 +542,19 @@ void PlayerPage::resizeEvent(QResizeEvent *event) {
|
|||
|
||||
if (m_expandedPad)
|
||||
m_expandedPad->setGeometry(0, 0, w, h);
|
||||
|
||||
if (m_btnHome) {
|
||||
int bw = w / 5;
|
||||
int bh = h / 4;
|
||||
int cy = h / 2 - bh / 2;
|
||||
m_btnHome->setGeometry(0, cy, bw, bh);
|
||||
m_btnHome->raise();
|
||||
}
|
||||
if (m_btnSettings) {
|
||||
int bw = w / 5;
|
||||
int bh = h / 4;
|
||||
int cy = h / 2 - bh / 2;
|
||||
m_btnSettings->setGeometry(w - bw, cy, bw, bh);
|
||||
m_btnSettings->raise();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,20 @@ private:
|
|||
std::function<QString(float, float)> m_colorFormatter;
|
||||
};
|
||||
|
||||
class SideButton : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Icon { Home, Settings };
|
||||
SideButton(Icon icon, QWidget *parent = nullptr);
|
||||
signals:
|
||||
void clicked();
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
void mousePressEvent(QMouseEvent *) override;
|
||||
private:
|
||||
Icon m_icon;
|
||||
};
|
||||
|
||||
class PlayerPage : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
@ -155,4 +169,6 @@ private:
|
|||
OverlayWidget *m_overlay;
|
||||
ExpandedXYPad *m_expandedPad = nullptr;
|
||||
bool m_expandedPadIsDsp = true;
|
||||
SideButton *m_btnHome = nullptr;
|
||||
SideButton *m_btnSettings = nullptr;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue