diff --git a/applications/Photoframe/dpf.ini b/applications/Photoframe/dpf.ini new file mode 100644 index 0000000..ebc90b9 --- /dev/null +++ b/applications/Photoframe/dpf.ini @@ -0,0 +1,5 @@ +[General] +Font=MammaGamma +Language=Korean +Background=image +ShowIntro=false \ No newline at end of file diff --git a/applications/Photoframe/dpf.ini b/applications/Photoframe/dpf.ini new file mode 100644 index 0000000..ebc90b9 --- /dev/null +++ b/applications/Photoframe/dpf.ini @@ -0,0 +1,5 @@ +[General] +Font=MammaGamma +Language=Korean +Background=image +ShowIntro=false \ No newline at end of file diff --git a/applications/Photoframe/src/mainmenu.cpp b/applications/Photoframe/src/mainmenu.cpp index 121c217..f9645a9 100755 --- a/applications/Photoframe/src/mainmenu.cpp +++ b/applications/Photoframe/src/mainmenu.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "mainmenu.h" #include "image.h" @@ -63,6 +66,9 @@ } +static const int frames = 15; + + class AnimatedIcon : public QWidget { public: @@ -72,57 +78,74 @@ ~AnimatedIcon() { // nothing } - void setPixmaps(int _a, int _b) { - a = Image::icon(iconMap[_a], 256); - b = Image::icon(iconMap[_b], 256); - ablur = blurPixmap(a); - bblur = blurPixmap(b); + template + void loadPixmp(std::string _name, QPixmap* _pix, F _loader) + { + if (!cache.find(_name.c_str(), _pix)) { + *_pix = _loader(_name.c_str()); + cache.insert(_name.c_str(), *_pix); + } } - void setFrame(int f) { + void setPixmaps(int _a, int _b) { + std::string blurSuffix = "_blur"; + loadPixmp(iconMap[_a], &a, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_b], &b, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_a] + blurSuffix, &ablur, [this](const char* _name) { return blurPixmap(a); }); + loadPixmp(iconMap[_b] + blurSuffix, &bblur, [this](const char* _name) { return blurPixmap(b); }); + } + void setFrame(int f, int d) { frame = f; + dir = d; } void paintEvent(QPaintEvent *pe) { QPainter p(this); QTransform trans; + + // QEasingCurve curve((dir == 1) ? QEasingCurve::OutInBack : QEasingCurve::InOutBack); + QEasingCurve curve((dir == 1) ? QEasingCurve::OutExpo: QEasingCurve::InExpo); + float curveValue = curve.valueForProgress(frame / float(frames)); + float invCurveValue = 1.0 - curveValue; float scale = 1.0; + float pos = invCurveValue * 200; // Draw icon 'a' trans.reset(); - scale = 0.5 + 0.5 * ((20.0 - frame) / 20.0); + scale = 0.5 + 0.5 * invCurveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity((20 - frame) / 20.0); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, 0, a); + p.setOpacity(invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, 0, a); p.resetTransform(); // Draw icon 'a' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * ((20 - frame) / 20.0)); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, -2.0 * a.height(), ablur); + p.setOpacity(0.3 * invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, -2.0 * a.height(), ablur); p.resetTransform(); // Draw icon 'b' trans.reset(); - scale = 0.5 + 0.5 * (frame / 20.0); + scale = 0.5 + 0.5 * curveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity(frame/20.0); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, 0, b); + p.setOpacity(curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, 0, b); p.resetTransform(); // Draw icon 'b' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * (frame / 20.0)); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, -2.0 * b.height(), bblur); + p.setOpacity(0.3 * curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, -2.0 * b.height(), bblur); p.resetTransform(); } + QPixmapCache cache; QPixmap a, b; QPixmap ablur, bblur; - int frame; + int frame, dir; }; @@ -136,12 +159,12 @@ curItem = 0; icon = new AnimatedIcon(this); - icon->setFrame(0); + icon->setFrame(0, 0); icon->setPixmaps(1,0); icon->setGeometry(menuLeft ? 320 : -70, labelAbove ? 150 : 80, 640, 600); icon->show(); icon->setPixmaps(0, 0); - icon->setFrame(0); + icon->setFrame(0, 0); icon->update(); item1 = new Text(this, menuLeft ? 432 : 82, labelAbove ? 52: 342, "", 40, QColor(0, 0, 0, 128)); @@ -157,6 +180,29 @@ frame = 0; QTimer::singleShot(0, this, SLOT(init())); + + QTimer* timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(35); + timer->callOnTimeout([this]() { + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + //icon->update(); + //update(); + //qApp->processEvents(); + icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } + }); + timer->start(); + + //timerId = startTimer(20, Qt::PreciseTimer); + animating = false; } @@ -185,14 +231,14 @@ void MainMenu::animate(int dir, int before, int now) { direction = dir; - killTimer(timerId); - if (dir == -1) - frame = 20; - else - frame = 0; + //killTimer(timerId); + animating = false; - icon->setFrame(frame); - icon->update(); + if (dir == -1) + frame = frames - 1;// 19; + else + frame = 1;// 1; + if (dir == -1) { item1->setText(nameMap[before]); item2->setText(nameMap[before]); @@ -200,19 +246,30 @@ item1->setText(nameMap[now]); item2->setText(nameMap[now]); } - - timerId = startTimer(15); + icon->setPixmaps(before, now); + icon->setFrame(frame, direction); + //update(); + //qApp->processEvents(); + //icon->repaint(); + + animating = true; } void MainMenu::timerEvent(QTimerEvent *te) { - frame += direction; - icon->setFrame(frame); - icon->update(); - if ( frame >= 20 || frame <= 0) - killTimer(timerId); + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + icon->update(); + //icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } } @@ -231,7 +288,7 @@ items[curItem]->select(); animate(-1, curItem, prevItem); if (!animateIcons) { - icon->setFrame(0); + icon->setFrame(0, -1); icon->update(); killTimer(timerId); } @@ -247,7 +304,7 @@ items[curItem]->select(); animate(1, prevItem, curItem); if (!animateIcons) { - icon->setFrame(20); + icon->setFrame(frames, 1); icon->update(); killTimer(timerId); } diff --git a/applications/Photoframe/dpf.ini b/applications/Photoframe/dpf.ini new file mode 100644 index 0000000..ebc90b9 --- /dev/null +++ b/applications/Photoframe/dpf.ini @@ -0,0 +1,5 @@ +[General] +Font=MammaGamma +Language=Korean +Background=image +ShowIntro=false \ No newline at end of file diff --git a/applications/Photoframe/src/mainmenu.cpp b/applications/Photoframe/src/mainmenu.cpp index 121c217..f9645a9 100755 --- a/applications/Photoframe/src/mainmenu.cpp +++ b/applications/Photoframe/src/mainmenu.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "mainmenu.h" #include "image.h" @@ -63,6 +66,9 @@ } +static const int frames = 15; + + class AnimatedIcon : public QWidget { public: @@ -72,57 +78,74 @@ ~AnimatedIcon() { // nothing } - void setPixmaps(int _a, int _b) { - a = Image::icon(iconMap[_a], 256); - b = Image::icon(iconMap[_b], 256); - ablur = blurPixmap(a); - bblur = blurPixmap(b); + template + void loadPixmp(std::string _name, QPixmap* _pix, F _loader) + { + if (!cache.find(_name.c_str(), _pix)) { + *_pix = _loader(_name.c_str()); + cache.insert(_name.c_str(), *_pix); + } } - void setFrame(int f) { + void setPixmaps(int _a, int _b) { + std::string blurSuffix = "_blur"; + loadPixmp(iconMap[_a], &a, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_b], &b, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_a] + blurSuffix, &ablur, [this](const char* _name) { return blurPixmap(a); }); + loadPixmp(iconMap[_b] + blurSuffix, &bblur, [this](const char* _name) { return blurPixmap(b); }); + } + void setFrame(int f, int d) { frame = f; + dir = d; } void paintEvent(QPaintEvent *pe) { QPainter p(this); QTransform trans; + + // QEasingCurve curve((dir == 1) ? QEasingCurve::OutInBack : QEasingCurve::InOutBack); + QEasingCurve curve((dir == 1) ? QEasingCurve::OutExpo: QEasingCurve::InExpo); + float curveValue = curve.valueForProgress(frame / float(frames)); + float invCurveValue = 1.0 - curveValue; float scale = 1.0; + float pos = invCurveValue * 200; // Draw icon 'a' trans.reset(); - scale = 0.5 + 0.5 * ((20.0 - frame) / 20.0); + scale = 0.5 + 0.5 * invCurveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity((20 - frame) / 20.0); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, 0, a); + p.setOpacity(invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, 0, a); p.resetTransform(); // Draw icon 'a' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * ((20 - frame) / 20.0)); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, -2.0 * a.height(), ablur); + p.setOpacity(0.3 * invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, -2.0 * a.height(), ablur); p.resetTransform(); // Draw icon 'b' trans.reset(); - scale = 0.5 + 0.5 * (frame / 20.0); + scale = 0.5 + 0.5 * curveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity(frame/20.0); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, 0, b); + p.setOpacity(curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, 0, b); p.resetTransform(); // Draw icon 'b' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * (frame / 20.0)); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, -2.0 * b.height(), bblur); + p.setOpacity(0.3 * curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, -2.0 * b.height(), bblur); p.resetTransform(); } + QPixmapCache cache; QPixmap a, b; QPixmap ablur, bblur; - int frame; + int frame, dir; }; @@ -136,12 +159,12 @@ curItem = 0; icon = new AnimatedIcon(this); - icon->setFrame(0); + icon->setFrame(0, 0); icon->setPixmaps(1,0); icon->setGeometry(menuLeft ? 320 : -70, labelAbove ? 150 : 80, 640, 600); icon->show(); icon->setPixmaps(0, 0); - icon->setFrame(0); + icon->setFrame(0, 0); icon->update(); item1 = new Text(this, menuLeft ? 432 : 82, labelAbove ? 52: 342, "", 40, QColor(0, 0, 0, 128)); @@ -157,6 +180,29 @@ frame = 0; QTimer::singleShot(0, this, SLOT(init())); + + QTimer* timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(35); + timer->callOnTimeout([this]() { + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + //icon->update(); + //update(); + //qApp->processEvents(); + icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } + }); + timer->start(); + + //timerId = startTimer(20, Qt::PreciseTimer); + animating = false; } @@ -185,14 +231,14 @@ void MainMenu::animate(int dir, int before, int now) { direction = dir; - killTimer(timerId); - if (dir == -1) - frame = 20; - else - frame = 0; + //killTimer(timerId); + animating = false; - icon->setFrame(frame); - icon->update(); + if (dir == -1) + frame = frames - 1;// 19; + else + frame = 1;// 1; + if (dir == -1) { item1->setText(nameMap[before]); item2->setText(nameMap[before]); @@ -200,19 +246,30 @@ item1->setText(nameMap[now]); item2->setText(nameMap[now]); } - - timerId = startTimer(15); + icon->setPixmaps(before, now); + icon->setFrame(frame, direction); + //update(); + //qApp->processEvents(); + //icon->repaint(); + + animating = true; } void MainMenu::timerEvent(QTimerEvent *te) { - frame += direction; - icon->setFrame(frame); - icon->update(); - if ( frame >= 20 || frame <= 0) - killTimer(timerId); + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + icon->update(); + //icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } } @@ -231,7 +288,7 @@ items[curItem]->select(); animate(-1, curItem, prevItem); if (!animateIcons) { - icon->setFrame(0); + icon->setFrame(0, -1); icon->update(); killTimer(timerId); } @@ -247,7 +304,7 @@ items[curItem]->select(); animate(1, prevItem, curItem); if (!animateIcons) { - icon->setFrame(20); + icon->setFrame(frames, 1); icon->update(); killTimer(timerId); } diff --git a/applications/Photoframe/src/mainmenu.h b/applications/Photoframe/src/mainmenu.h index 3ddec71..f0b4206 100755 --- a/applications/Photoframe/src/mainmenu.h +++ b/applications/Photoframe/src/mainmenu.h @@ -33,6 +33,7 @@ Text *item1, *item2; int direction; bool animateIcons; + bool animating; }; diff --git a/applications/Photoframe/dpf.ini b/applications/Photoframe/dpf.ini new file mode 100644 index 0000000..ebc90b9 --- /dev/null +++ b/applications/Photoframe/dpf.ini @@ -0,0 +1,5 @@ +[General] +Font=MammaGamma +Language=Korean +Background=image +ShowIntro=false \ No newline at end of file diff --git a/applications/Photoframe/src/mainmenu.cpp b/applications/Photoframe/src/mainmenu.cpp index 121c217..f9645a9 100755 --- a/applications/Photoframe/src/mainmenu.cpp +++ b/applications/Photoframe/src/mainmenu.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "mainmenu.h" #include "image.h" @@ -63,6 +66,9 @@ } +static const int frames = 15; + + class AnimatedIcon : public QWidget { public: @@ -72,57 +78,74 @@ ~AnimatedIcon() { // nothing } - void setPixmaps(int _a, int _b) { - a = Image::icon(iconMap[_a], 256); - b = Image::icon(iconMap[_b], 256); - ablur = blurPixmap(a); - bblur = blurPixmap(b); + template + void loadPixmp(std::string _name, QPixmap* _pix, F _loader) + { + if (!cache.find(_name.c_str(), _pix)) { + *_pix = _loader(_name.c_str()); + cache.insert(_name.c_str(), *_pix); + } } - void setFrame(int f) { + void setPixmaps(int _a, int _b) { + std::string blurSuffix = "_blur"; + loadPixmp(iconMap[_a], &a, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_b], &b, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_a] + blurSuffix, &ablur, [this](const char* _name) { return blurPixmap(a); }); + loadPixmp(iconMap[_b] + blurSuffix, &bblur, [this](const char* _name) { return blurPixmap(b); }); + } + void setFrame(int f, int d) { frame = f; + dir = d; } void paintEvent(QPaintEvent *pe) { QPainter p(this); QTransform trans; + + // QEasingCurve curve((dir == 1) ? QEasingCurve::OutInBack : QEasingCurve::InOutBack); + QEasingCurve curve((dir == 1) ? QEasingCurve::OutExpo: QEasingCurve::InExpo); + float curveValue = curve.valueForProgress(frame / float(frames)); + float invCurveValue = 1.0 - curveValue; float scale = 1.0; + float pos = invCurveValue * 200; // Draw icon 'a' trans.reset(); - scale = 0.5 + 0.5 * ((20.0 - frame) / 20.0); + scale = 0.5 + 0.5 * invCurveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity((20 - frame) / 20.0); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, 0, a); + p.setOpacity(invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, 0, a); p.resetTransform(); // Draw icon 'a' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * ((20 - frame) / 20.0)); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, -2.0 * a.height(), ablur); + p.setOpacity(0.3 * invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, -2.0 * a.height(), ablur); p.resetTransform(); // Draw icon 'b' trans.reset(); - scale = 0.5 + 0.5 * (frame / 20.0); + scale = 0.5 + 0.5 * curveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity(frame/20.0); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, 0, b); + p.setOpacity(curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, 0, b); p.resetTransform(); // Draw icon 'b' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * (frame / 20.0)); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, -2.0 * b.height(), bblur); + p.setOpacity(0.3 * curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, -2.0 * b.height(), bblur); p.resetTransform(); } + QPixmapCache cache; QPixmap a, b; QPixmap ablur, bblur; - int frame; + int frame, dir; }; @@ -136,12 +159,12 @@ curItem = 0; icon = new AnimatedIcon(this); - icon->setFrame(0); + icon->setFrame(0, 0); icon->setPixmaps(1,0); icon->setGeometry(menuLeft ? 320 : -70, labelAbove ? 150 : 80, 640, 600); icon->show(); icon->setPixmaps(0, 0); - icon->setFrame(0); + icon->setFrame(0, 0); icon->update(); item1 = new Text(this, menuLeft ? 432 : 82, labelAbove ? 52: 342, "", 40, QColor(0, 0, 0, 128)); @@ -157,6 +180,29 @@ frame = 0; QTimer::singleShot(0, this, SLOT(init())); + + QTimer* timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(35); + timer->callOnTimeout([this]() { + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + //icon->update(); + //update(); + //qApp->processEvents(); + icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } + }); + timer->start(); + + //timerId = startTimer(20, Qt::PreciseTimer); + animating = false; } @@ -185,14 +231,14 @@ void MainMenu::animate(int dir, int before, int now) { direction = dir; - killTimer(timerId); - if (dir == -1) - frame = 20; - else - frame = 0; + //killTimer(timerId); + animating = false; - icon->setFrame(frame); - icon->update(); + if (dir == -1) + frame = frames - 1;// 19; + else + frame = 1;// 1; + if (dir == -1) { item1->setText(nameMap[before]); item2->setText(nameMap[before]); @@ -200,19 +246,30 @@ item1->setText(nameMap[now]); item2->setText(nameMap[now]); } - - timerId = startTimer(15); + icon->setPixmaps(before, now); + icon->setFrame(frame, direction); + //update(); + //qApp->processEvents(); + //icon->repaint(); + + animating = true; } void MainMenu::timerEvent(QTimerEvent *te) { - frame += direction; - icon->setFrame(frame); - icon->update(); - if ( frame >= 20 || frame <= 0) - killTimer(timerId); + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + icon->update(); + //icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } } @@ -231,7 +288,7 @@ items[curItem]->select(); animate(-1, curItem, prevItem); if (!animateIcons) { - icon->setFrame(0); + icon->setFrame(0, -1); icon->update(); killTimer(timerId); } @@ -247,7 +304,7 @@ items[curItem]->select(); animate(1, prevItem, curItem); if (!animateIcons) { - icon->setFrame(20); + icon->setFrame(frames, 1); icon->update(); killTimer(timerId); } diff --git a/applications/Photoframe/src/mainmenu.h b/applications/Photoframe/src/mainmenu.h index 3ddec71..f0b4206 100755 --- a/applications/Photoframe/src/mainmenu.h +++ b/applications/Photoframe/src/mainmenu.h @@ -33,6 +33,7 @@ Text *item1, *item2; int direction; bool animateIcons; + bool animating; }; diff --git a/applications/Photoframe/src/manager.cpp b/applications/Photoframe/src/manager.cpp index 1da7590..5f9f682 100755 --- a/applications/Photoframe/src/manager.cpp +++ b/applications/Photoframe/src/manager.cpp @@ -72,12 +72,16 @@ group->addAnimation(anim2); } + //connect(group, &QAnimationGroup::finished, [w]() { w->setGraphicsEffect(nullptr); }); group->start(QAbstractAnimation::DeleteWhenStopped); } void Manager::fadeOutWidget(QWidget* w) { + if (!w->isVisible()) + return; + QGraphicsOpacityEffect* eff = new QGraphicsOpacityEffect(this); w->setGraphicsEffect(eff); @@ -105,7 +109,7 @@ group->addAnimation(anim2); } - connect(group, &QAnimationGroup::finished, [w, icon]() { w->hide(); if (icon) icon->hide(); }); + connect(group, &QAnimationGroup::finished, [w, icon]() { /* w->setGraphicsEffect(nullptr); */ w->hide(); if (icon) icon->hide(); }); group->start(QAbstractAnimation::DeleteWhenStopped); } @@ -132,6 +136,7 @@ mainmenu->setFocus(); break; case 0: + //delete slideshow; slideshow = 0; if (!slideshow) { slideshow = new SlideShow(this); connect(slideshow, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -139,13 +144,16 @@ fadeInWidget(slideshow); break; case 1: - if (!photos) { + //delete photos; photos = 0; + if (!photos) + { photos = new PhotoList(this); connect(photos, SIGNAL(setStage(int)), this, SLOT(setStage(int))); } fadeInWidget(photos); break; case 2: + //delete music; music = 0; if (!music) { music = new MusicList(this); connect(music, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -153,6 +161,7 @@ fadeInWidget(music); break; case 3: + //delete videos; videos = 0; if (!videos) { videos = new VideoList(this); connect(videos, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -160,6 +169,7 @@ fadeInWidget(videos); break; case 4: + //delete info; info = 0; if (!info) { info = new Information(this); connect(info, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -167,6 +177,7 @@ fadeInWidget(info); break; case 5: + //delete settings; settings = 0; if (!settings) { settings = new Settings(this); connect(settings, SIGNAL(setStage(int)), this, SLOT(setStage(int))); diff --git a/applications/Photoframe/dpf.ini b/applications/Photoframe/dpf.ini new file mode 100644 index 0000000..ebc90b9 --- /dev/null +++ b/applications/Photoframe/dpf.ini @@ -0,0 +1,5 @@ +[General] +Font=MammaGamma +Language=Korean +Background=image +ShowIntro=false \ No newline at end of file diff --git a/applications/Photoframe/src/mainmenu.cpp b/applications/Photoframe/src/mainmenu.cpp index 121c217..f9645a9 100755 --- a/applications/Photoframe/src/mainmenu.cpp +++ b/applications/Photoframe/src/mainmenu.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "mainmenu.h" #include "image.h" @@ -63,6 +66,9 @@ } +static const int frames = 15; + + class AnimatedIcon : public QWidget { public: @@ -72,57 +78,74 @@ ~AnimatedIcon() { // nothing } - void setPixmaps(int _a, int _b) { - a = Image::icon(iconMap[_a], 256); - b = Image::icon(iconMap[_b], 256); - ablur = blurPixmap(a); - bblur = blurPixmap(b); + template + void loadPixmp(std::string _name, QPixmap* _pix, F _loader) + { + if (!cache.find(_name.c_str(), _pix)) { + *_pix = _loader(_name.c_str()); + cache.insert(_name.c_str(), *_pix); + } } - void setFrame(int f) { + void setPixmaps(int _a, int _b) { + std::string blurSuffix = "_blur"; + loadPixmp(iconMap[_a], &a, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_b], &b, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_a] + blurSuffix, &ablur, [this](const char* _name) { return blurPixmap(a); }); + loadPixmp(iconMap[_b] + blurSuffix, &bblur, [this](const char* _name) { return blurPixmap(b); }); + } + void setFrame(int f, int d) { frame = f; + dir = d; } void paintEvent(QPaintEvent *pe) { QPainter p(this); QTransform trans; + + // QEasingCurve curve((dir == 1) ? QEasingCurve::OutInBack : QEasingCurve::InOutBack); + QEasingCurve curve((dir == 1) ? QEasingCurve::OutExpo: QEasingCurve::InExpo); + float curveValue = curve.valueForProgress(frame / float(frames)); + float invCurveValue = 1.0 - curveValue; float scale = 1.0; + float pos = invCurveValue * 200; // Draw icon 'a' trans.reset(); - scale = 0.5 + 0.5 * ((20.0 - frame) / 20.0); + scale = 0.5 + 0.5 * invCurveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity((20 - frame) / 20.0); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, 0, a); + p.setOpacity(invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, 0, a); p.resetTransform(); // Draw icon 'a' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * ((20 - frame) / 20.0)); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, -2.0 * a.height(), ablur); + p.setOpacity(0.3 * invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, -2.0 * a.height(), ablur); p.resetTransform(); // Draw icon 'b' trans.reset(); - scale = 0.5 + 0.5 * (frame / 20.0); + scale = 0.5 + 0.5 * curveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity(frame/20.0); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, 0, b); + p.setOpacity(curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, 0, b); p.resetTransform(); // Draw icon 'b' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * (frame / 20.0)); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, -2.0 * b.height(), bblur); + p.setOpacity(0.3 * curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, -2.0 * b.height(), bblur); p.resetTransform(); } + QPixmapCache cache; QPixmap a, b; QPixmap ablur, bblur; - int frame; + int frame, dir; }; @@ -136,12 +159,12 @@ curItem = 0; icon = new AnimatedIcon(this); - icon->setFrame(0); + icon->setFrame(0, 0); icon->setPixmaps(1,0); icon->setGeometry(menuLeft ? 320 : -70, labelAbove ? 150 : 80, 640, 600); icon->show(); icon->setPixmaps(0, 0); - icon->setFrame(0); + icon->setFrame(0, 0); icon->update(); item1 = new Text(this, menuLeft ? 432 : 82, labelAbove ? 52: 342, "", 40, QColor(0, 0, 0, 128)); @@ -157,6 +180,29 @@ frame = 0; QTimer::singleShot(0, this, SLOT(init())); + + QTimer* timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(35); + timer->callOnTimeout([this]() { + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + //icon->update(); + //update(); + //qApp->processEvents(); + icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } + }); + timer->start(); + + //timerId = startTimer(20, Qt::PreciseTimer); + animating = false; } @@ -185,14 +231,14 @@ void MainMenu::animate(int dir, int before, int now) { direction = dir; - killTimer(timerId); - if (dir == -1) - frame = 20; - else - frame = 0; + //killTimer(timerId); + animating = false; - icon->setFrame(frame); - icon->update(); + if (dir == -1) + frame = frames - 1;// 19; + else + frame = 1;// 1; + if (dir == -1) { item1->setText(nameMap[before]); item2->setText(nameMap[before]); @@ -200,19 +246,30 @@ item1->setText(nameMap[now]); item2->setText(nameMap[now]); } - - timerId = startTimer(15); + icon->setPixmaps(before, now); + icon->setFrame(frame, direction); + //update(); + //qApp->processEvents(); + //icon->repaint(); + + animating = true; } void MainMenu::timerEvent(QTimerEvent *te) { - frame += direction; - icon->setFrame(frame); - icon->update(); - if ( frame >= 20 || frame <= 0) - killTimer(timerId); + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + icon->update(); + //icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } } @@ -231,7 +288,7 @@ items[curItem]->select(); animate(-1, curItem, prevItem); if (!animateIcons) { - icon->setFrame(0); + icon->setFrame(0, -1); icon->update(); killTimer(timerId); } @@ -247,7 +304,7 @@ items[curItem]->select(); animate(1, prevItem, curItem); if (!animateIcons) { - icon->setFrame(20); + icon->setFrame(frames, 1); icon->update(); killTimer(timerId); } diff --git a/applications/Photoframe/src/mainmenu.h b/applications/Photoframe/src/mainmenu.h index 3ddec71..f0b4206 100755 --- a/applications/Photoframe/src/mainmenu.h +++ b/applications/Photoframe/src/mainmenu.h @@ -33,6 +33,7 @@ Text *item1, *item2; int direction; bool animateIcons; + bool animating; }; diff --git a/applications/Photoframe/src/manager.cpp b/applications/Photoframe/src/manager.cpp index 1da7590..5f9f682 100755 --- a/applications/Photoframe/src/manager.cpp +++ b/applications/Photoframe/src/manager.cpp @@ -72,12 +72,16 @@ group->addAnimation(anim2); } + //connect(group, &QAnimationGroup::finished, [w]() { w->setGraphicsEffect(nullptr); }); group->start(QAbstractAnimation::DeleteWhenStopped); } void Manager::fadeOutWidget(QWidget* w) { + if (!w->isVisible()) + return; + QGraphicsOpacityEffect* eff = new QGraphicsOpacityEffect(this); w->setGraphicsEffect(eff); @@ -105,7 +109,7 @@ group->addAnimation(anim2); } - connect(group, &QAnimationGroup::finished, [w, icon]() { w->hide(); if (icon) icon->hide(); }); + connect(group, &QAnimationGroup::finished, [w, icon]() { /* w->setGraphicsEffect(nullptr); */ w->hide(); if (icon) icon->hide(); }); group->start(QAbstractAnimation::DeleteWhenStopped); } @@ -132,6 +136,7 @@ mainmenu->setFocus(); break; case 0: + //delete slideshow; slideshow = 0; if (!slideshow) { slideshow = new SlideShow(this); connect(slideshow, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -139,13 +144,16 @@ fadeInWidget(slideshow); break; case 1: - if (!photos) { + //delete photos; photos = 0; + if (!photos) + { photos = new PhotoList(this); connect(photos, SIGNAL(setStage(int)), this, SLOT(setStage(int))); } fadeInWidget(photos); break; case 2: + //delete music; music = 0; if (!music) { music = new MusicList(this); connect(music, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -153,6 +161,7 @@ fadeInWidget(music); break; case 3: + //delete videos; videos = 0; if (!videos) { videos = new VideoList(this); connect(videos, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -160,6 +169,7 @@ fadeInWidget(videos); break; case 4: + //delete info; info = 0; if (!info) { info = new Information(this); connect(info, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -167,6 +177,7 @@ fadeInWidget(info); break; case 5: + //delete settings; settings = 0; if (!settings) { settings = new Settings(this); connect(settings, SIGNAL(setStage(int)), this, SLOT(setStage(int))); diff --git a/applications/Photoframe/src/videolist.cpp b/applications/Photoframe/src/videolist.cpp index 2b47768..92e8ec9 100755 --- a/applications/Photoframe/src/videolist.cpp +++ b/applications/Photoframe/src/videolist.cpp @@ -1,7 +1,170 @@ #include "videolist.h" #include "devicelist.h" #include "text.h" +#include +#include #include +#include +#include +#include +#include +#include + + +using KeyValuePairs = std::unordered_map; +using Json = QJsonDocument; + + +class Response +{ +public: + Response() {} + Response(QByteArray _ba) : ba(_ba) {} + Response(const Response& other) : ba(other.ba) {} + Json json() { + return QJsonDocument::fromJson(ba); + } +private: + QByteArray ba; +}; + + +class Requests : public QObject +{ +public: + Requests() + { + manager = new QNetworkAccessManager(); + + QObject::connect(manager, &QNetworkAccessManager::finished, + this, [=](QNetworkReply* reply) + { + if (reply->error()) { + qDebug() << reply->errorString(); + return; + } + + if (continuationMap.count(reply)) + { + Response resp(reply->readAll()); + continuationMap[reply](resp); + } + }); + } + + ~Requests() + { + delete manager; + } + + // sessions? + void get(const std::string& url, const KeyValuePairs& headers, std::function continuation) + { + QNetworkRequest request; + request.setUrl(QUrl(url.c_str())); + auto resp = manager->get(request); + continuationMap[resp] = continuation; + } + +private: + QNetworkAccessManager* manager; + std::unordered_map> continuationMap; +}; + + +class MovieAggregator : public QObject +{ +}; + + +class JustWatch : public MovieAggregator +{ + static std::string api_base_template; +public: + JustWatch(const char* _country = "US")//, bool _use_sessions = true) + { + requests = new Requests; + // self.kwargs = kwargs + country = _country; + //self.kwargs_cinema = [] + setupLocale(); + } + + ~JustWatch() + { + delete requests; + } + + void setupLocale(); + + void searchForItem(std::string query, KeyValuePairs kwargs); + void getProviders(); + void getGenres(); + void getTitle(std::string title_id, std::string content_type = "movie"); + void searchTitleId(std::string query); + void getSeason(std::string season_id); + void getCinemaTimes(std::string title_id, std::string content_type = "movie", KeyValuePairs kwargs = {}); + void getCinemaDetails(KeyValuePairs kwargs); + void getUpcomingCinema(int weeks_offset, bool nationwide_cinema_releases_only = true); + void getCertifications(std::string content_type = "movie"); + void getPersonCetail(std::string person_id); + +private: + Requests* requests; + std::string country; + std::string locale; +}; + + +void JustWatch::setupLocale() +{ + std::string default_locale = "en_AU"; + std::string api_url = api_base_template + "locales/state"; + KeyValuePairs headers = { { "User - Agent", "JustWatch client(github.com / dawoudt / JustWatchAPI)" } }; + requests->get(api_url, headers, [=](Response& resp) + { + std::string str = resp.json().toJson(QJsonDocument::Indented).toStdString(); + qDebug() << str.c_str(); + + locale = default_locale; + auto results = resp.json(); + //QJsonArray arr; + for (auto result : results.array()) + if ((result.toObject()["iso_3166_2"].toString().toStdString() == country) + || (result.toObject()["country"].toString().toStdString() == country)) + locale = result.toObject()["full_locale"].toString().toStdString(); + }); + + // warn = '\nWARN: Unable to locale for {}! Defaulting to en_AU\n' + //sys.stderr.write(warn.format(self.country)) + //return default_locale; +} + + +std::string JustWatch::api_base_template = "http://apis.justwatch.com/content/";// {path}"; + + +class VideoManager : public QObject +{ +public: + VideoManager(); + ~VideoManager() {} + + void getList(); + +private: + JustWatch justWatch; +}; + + +VideoManager::VideoManager() +{ +} + + +void VideoManager::getList() +{ +} VideoList::VideoList(QWidget *parent) : QWidget(parent) @@ -15,12 +178,14 @@ devices->setFocus(); new Text(this, 380+2, 230+2, "Not Implemented", 20, QColor(0,0,0,128)); new Text(this, 380, 230, "Not Implemented", 20); + + manager = new VideoManager; } VideoList::~VideoList() { - + delete manager; } @@ -30,3 +195,264 @@ devices->setFocus(); } + + + +#if 0 + +JustWatch API + + +from datetime import datetime +from datetime import timedelta +import requests +import sys + + +HEADER = { 'User-Agent':'JustWatch client (github.com/dawoudt/JustWatchAPI)' } + + +class JustWatch : + api_base_template = "https://apis.justwatch.com/content/{path}" + + def __init__(self, country = 'AU', use_sessions = True, **kwargs) : + self.kwargs = kwargs + self.country = country + self.kwargs_cinema = [] + self.requests = requests.Session() if use_sessions else requests + self.locale = self.set_locale() + + + def __del__(self) : + ''' Should really use context manager + but this should do without changing functionality. + ''' + if isinstance(self.requests, requests.Session) : + self.requests.close() + + + def set_locale(self) : + warn = '\nWARN: Unable to locale for {}! Defaulting to en_AU\n' + default_locale = 'en_AU' + path = 'locales/state' + api_url = self.api_base_template.format(path = path) + + r = self.requests.get(api_url, headers = HEADER) + try : + r.raise_for_status() + except requests.exceptions.HTTPError : + sys.stderr.write(warn.format(self.country)) + return default_locale + else: +results = r.json() + +for result in results : +if result['iso_3166_2'] == self.country or \ +result['country'] == self.country: + +return result['full_locale'] + +sys.stderr.write(warn.format(self.country)) +return default_locale + +def search_for_item(self, query = None, **kwargs) : + + path = 'titles/{}/popular'.format(self.locale) + api_url = self.api_base_template.format(path = path) + + if kwargs : + self.kwargs = kwargs + if query : + self.kwargs.update({ 'query': query }) + null = None + payload = { + "age_certifications":null, + "content_types" : null, + "presentation_types" : null, + "providers" : null, + "genres" : null, + "languages" : null, + "release_year_from" : null, + "release_year_until" : null, + "monetization_types" : null, + "min_price" : null, + "max_price" : null, + "nationwide_cinema_releases_only" : null, + "scoring_filter_types" : null, + "cinema_release" : null, + "query" : null, + "page" : null, + "page_size" : null, + "timeline_type" : null, + "person_id" : null + } + for key, value in self.kwargs.items() : + if key in payload.keys() : + payload[key] = value + else : + print('{} is not a valid keyword'.format(key)) + r = self.requests.post(api_url, json = payload, headers = HEADER) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_providers(self) : + path = 'providers/locale/{}'.format(self.locale) + api_url = self.api_base_template.format(path = path) + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_genres(self) : + path = 'genres/locale/{}'.format(self.locale) + api_url = self.api_base_template.format(path = path) + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_title(self, title_id, content_type = 'movie') : + path = 'titles/{content_type}/{title_id}/locale/{locale}'.format(content_type = content_type, + title_id = title_id, + locale = self.locale) + + api_url = self.api_base_template.format(path = path) + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def search_title_id(self, query) : + ''' Returns a dictionary of titles returned + from search and their respective ID's + + >> > ... + >> > just_watch.get_title_id('The Matrix') + { + 'The Matrix': 10, ... + } + +''' + +results = self.search_for_item(query) +return { item['id']: item['title'] for item in results['items'] } + + +def get_season(self, season_id) : + + header = HEADER + api_url = 'https://apis.justwatch.com/content/titles/show_season/{}/locale/{}'.format(season_id, self.locale) + r = self.requests.get(api_url, headers = header) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + + def get_cinema_times(self, title_id, content_type = 'movie', **kwargs) : + + if kwargs : + self.kwargs_cinema = kwargs + + null = None + payload = { + "date":null, + "latitude" : null, + "longitude" : null, + "radius" : 20000 + } + for key, value in self.kwargs_cinema.items() : + if key in payload.keys() : + payload[key] = value + else : + print('{} is not a valid keyword'.format(key)) + + + header = HEADER + api_url = 'https://apis.justwatch.com/content/titles/{}/{}/showtimes'.format(content_type, title_id) + r = self.requests.get(api_url, params = payload, headers = header) + + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + + def get_cinema_details(self, **kwargs) : + + if kwargs : + self.kwargs_cinema = kwargs + + null = None + payload = { + "latitude":null, + "longitude" : null, + "radius" : 20000 + } + for key, value in self.kwargs_cinema.items() : + if key in payload.keys() : + payload[key] = value + elif key == 'date' : + #ignore the date value if passed + pass + else: +print('{} is not a valid keyword'.format(key)) + + +header = HEADER +api_url = 'https://apis.justwatch.com/content/cinemas/{}'.format(self.locale) +r = self.requests.get(api_url, params = payload, headers = header) + +r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + +return r.json() + + + +def get_upcoming_cinema(self, weeks_offset, nationwide_cinema_releases_only = True) : + + header = HEADER + payload = { 'nationwide_cinema_releases_only': nationwide_cinema_releases_only, + 'body' : {} } + now_date = datetime.now() + td = timedelta(weeks = weeks_offset) + year_month_day = (now_date + td).isocalendar() + api_url = 'https://apis.justwatch.com/content/titles/movie/upcoming/{}/{}/locale/{}' + api_url = api_url.format(year_month_day[0], year_month_day[1], self.locale) + + #this throws an error if you go too many weeks forward, so return a blank payload if we hit an error + try : + r = self.requests.get(api_url, params = payload, headers = header) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + except: +return { 'page': 0, 'page_size' : 0, 'total_pages' : 1, 'total_results' : 0, 'items' : [] } + +def get_certifications(self, content_type = 'movie') : + + header = HEADER + payload = { 'country': self.country, 'object_type' : content_type } + api_url = 'https://apis.justwatch.com/content/age_certifications' + r = self.requests.get(api_url, params = payload, headers = header) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_person_detail(self, person_id) : + path = 'titles/person/{person_id}/locale/{locale}'.format(person_id = person_id, locale = self.locale) + api_url = self.api_base_template.format(path = path) + + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + +#endif diff --git a/applications/Photoframe/dpf.ini b/applications/Photoframe/dpf.ini new file mode 100644 index 0000000..ebc90b9 --- /dev/null +++ b/applications/Photoframe/dpf.ini @@ -0,0 +1,5 @@ +[General] +Font=MammaGamma +Language=Korean +Background=image +ShowIntro=false \ No newline at end of file diff --git a/applications/Photoframe/src/mainmenu.cpp b/applications/Photoframe/src/mainmenu.cpp index 121c217..f9645a9 100755 --- a/applications/Photoframe/src/mainmenu.cpp +++ b/applications/Photoframe/src/mainmenu.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "mainmenu.h" #include "image.h" @@ -63,6 +66,9 @@ } +static const int frames = 15; + + class AnimatedIcon : public QWidget { public: @@ -72,57 +78,74 @@ ~AnimatedIcon() { // nothing } - void setPixmaps(int _a, int _b) { - a = Image::icon(iconMap[_a], 256); - b = Image::icon(iconMap[_b], 256); - ablur = blurPixmap(a); - bblur = blurPixmap(b); + template + void loadPixmp(std::string _name, QPixmap* _pix, F _loader) + { + if (!cache.find(_name.c_str(), _pix)) { + *_pix = _loader(_name.c_str()); + cache.insert(_name.c_str(), *_pix); + } } - void setFrame(int f) { + void setPixmaps(int _a, int _b) { + std::string blurSuffix = "_blur"; + loadPixmp(iconMap[_a], &a, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_b], &b, [](const char* _name) { return Image::icon(_name, 256); }); + loadPixmp(iconMap[_a] + blurSuffix, &ablur, [this](const char* _name) { return blurPixmap(a); }); + loadPixmp(iconMap[_b] + blurSuffix, &bblur, [this](const char* _name) { return blurPixmap(b); }); + } + void setFrame(int f, int d) { frame = f; + dir = d; } void paintEvent(QPaintEvent *pe) { QPainter p(this); QTransform trans; + + // QEasingCurve curve((dir == 1) ? QEasingCurve::OutInBack : QEasingCurve::InOutBack); + QEasingCurve curve((dir == 1) ? QEasingCurve::OutExpo: QEasingCurve::InExpo); + float curveValue = curve.valueForProgress(frame / float(frames)); + float invCurveValue = 1.0 - curveValue; float scale = 1.0; + float pos = invCurveValue * 200; // Draw icon 'a' trans.reset(); - scale = 0.5 + 0.5 * ((20.0 - frame) / 20.0); + scale = 0.5 + 0.5 * invCurveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity((20 - frame) / 20.0); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, 0, a); + p.setOpacity(invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, 0, a); p.resetTransform(); // Draw icon 'a' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * ((20 - frame) / 20.0)); - p.drawPixmap(380 * (1.0 - scale) + 160 - frame * 10, -2.0 * a.height(), ablur); + p.setOpacity(0.3 * invCurveValue); + p.drawPixmap(360 * (1.0 - scale) - 40 + pos, -2.0 * a.height(), ablur); p.resetTransform(); // Draw icon 'b' trans.reset(); - scale = 0.5 + 0.5 * (frame / 20.0); + scale = 0.5 + 0.5 * curveValue; trans.scale(scale, scale); p.setWorldTransform(trans); - p.setOpacity(frame/20.0); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, 0, b); + p.setOpacity(curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, 0, b); p.resetTransform(); // Draw icon 'b' reflected trans.reset(); trans.scale(scale, -scale); p.setWorldTransform(trans); - p.setOpacity(0.3 * (frame / 20.0)); - p.drawPixmap(720 * (1.0 - scale) + 360 - frame * 10, -2.0 * b.height(), bblur); + p.setOpacity(0.3 * curveValue); + p.drawPixmap(700 * (1.0 - scale) + 160 + pos, -2.0 * b.height(), bblur); p.resetTransform(); } + QPixmapCache cache; QPixmap a, b; QPixmap ablur, bblur; - int frame; + int frame, dir; }; @@ -136,12 +159,12 @@ curItem = 0; icon = new AnimatedIcon(this); - icon->setFrame(0); + icon->setFrame(0, 0); icon->setPixmaps(1,0); icon->setGeometry(menuLeft ? 320 : -70, labelAbove ? 150 : 80, 640, 600); icon->show(); icon->setPixmaps(0, 0); - icon->setFrame(0); + icon->setFrame(0, 0); icon->update(); item1 = new Text(this, menuLeft ? 432 : 82, labelAbove ? 52: 342, "", 40, QColor(0, 0, 0, 128)); @@ -157,6 +180,29 @@ frame = 0; QTimer::singleShot(0, this, SLOT(init())); + + QTimer* timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(35); + timer->callOnTimeout([this]() { + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + //icon->update(); + //update(); + //qApp->processEvents(); + icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } + }); + timer->start(); + + //timerId = startTimer(20, Qt::PreciseTimer); + animating = false; } @@ -185,14 +231,14 @@ void MainMenu::animate(int dir, int before, int now) { direction = dir; - killTimer(timerId); - if (dir == -1) - frame = 20; - else - frame = 0; + //killTimer(timerId); + animating = false; - icon->setFrame(frame); - icon->update(); + if (dir == -1) + frame = frames - 1;// 19; + else + frame = 1;// 1; + if (dir == -1) { item1->setText(nameMap[before]); item2->setText(nameMap[before]); @@ -200,19 +246,30 @@ item1->setText(nameMap[now]); item2->setText(nameMap[now]); } - - timerId = startTimer(15); + icon->setPixmaps(before, now); + icon->setFrame(frame, direction); + //update(); + //qApp->processEvents(); + //icon->repaint(); + + animating = true; } void MainMenu::timerEvent(QTimerEvent *te) { - frame += direction; - icon->setFrame(frame); - icon->update(); - if ( frame >= 20 || frame <= 0) - killTimer(timerId); + if (animating) + { + frame += direction; + icon->setFrame(frame, direction); + icon->update(); + //icon->repaint(); + + if (frame >= frames || frame <= 0) + animating = false; + //killTimer(timerId); + } } @@ -231,7 +288,7 @@ items[curItem]->select(); animate(-1, curItem, prevItem); if (!animateIcons) { - icon->setFrame(0); + icon->setFrame(0, -1); icon->update(); killTimer(timerId); } @@ -247,7 +304,7 @@ items[curItem]->select(); animate(1, prevItem, curItem); if (!animateIcons) { - icon->setFrame(20); + icon->setFrame(frames, 1); icon->update(); killTimer(timerId); } diff --git a/applications/Photoframe/src/mainmenu.h b/applications/Photoframe/src/mainmenu.h index 3ddec71..f0b4206 100755 --- a/applications/Photoframe/src/mainmenu.h +++ b/applications/Photoframe/src/mainmenu.h @@ -33,6 +33,7 @@ Text *item1, *item2; int direction; bool animateIcons; + bool animating; }; diff --git a/applications/Photoframe/src/manager.cpp b/applications/Photoframe/src/manager.cpp index 1da7590..5f9f682 100755 --- a/applications/Photoframe/src/manager.cpp +++ b/applications/Photoframe/src/manager.cpp @@ -72,12 +72,16 @@ group->addAnimation(anim2); } + //connect(group, &QAnimationGroup::finished, [w]() { w->setGraphicsEffect(nullptr); }); group->start(QAbstractAnimation::DeleteWhenStopped); } void Manager::fadeOutWidget(QWidget* w) { + if (!w->isVisible()) + return; + QGraphicsOpacityEffect* eff = new QGraphicsOpacityEffect(this); w->setGraphicsEffect(eff); @@ -105,7 +109,7 @@ group->addAnimation(anim2); } - connect(group, &QAnimationGroup::finished, [w, icon]() { w->hide(); if (icon) icon->hide(); }); + connect(group, &QAnimationGroup::finished, [w, icon]() { /* w->setGraphicsEffect(nullptr); */ w->hide(); if (icon) icon->hide(); }); group->start(QAbstractAnimation::DeleteWhenStopped); } @@ -132,6 +136,7 @@ mainmenu->setFocus(); break; case 0: + //delete slideshow; slideshow = 0; if (!slideshow) { slideshow = new SlideShow(this); connect(slideshow, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -139,13 +144,16 @@ fadeInWidget(slideshow); break; case 1: - if (!photos) { + //delete photos; photos = 0; + if (!photos) + { photos = new PhotoList(this); connect(photos, SIGNAL(setStage(int)), this, SLOT(setStage(int))); } fadeInWidget(photos); break; case 2: + //delete music; music = 0; if (!music) { music = new MusicList(this); connect(music, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -153,6 +161,7 @@ fadeInWidget(music); break; case 3: + //delete videos; videos = 0; if (!videos) { videos = new VideoList(this); connect(videos, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -160,6 +169,7 @@ fadeInWidget(videos); break; case 4: + //delete info; info = 0; if (!info) { info = new Information(this); connect(info, SIGNAL(setStage(int)), this, SLOT(setStage(int))); @@ -167,6 +177,7 @@ fadeInWidget(info); break; case 5: + //delete settings; settings = 0; if (!settings) { settings = new Settings(this); connect(settings, SIGNAL(setStage(int)), this, SLOT(setStage(int))); diff --git a/applications/Photoframe/src/videolist.cpp b/applications/Photoframe/src/videolist.cpp index 2b47768..92e8ec9 100755 --- a/applications/Photoframe/src/videolist.cpp +++ b/applications/Photoframe/src/videolist.cpp @@ -1,7 +1,170 @@ #include "videolist.h" #include "devicelist.h" #include "text.h" +#include +#include #include +#include +#include +#include +#include +#include + + +using KeyValuePairs = std::unordered_map; +using Json = QJsonDocument; + + +class Response +{ +public: + Response() {} + Response(QByteArray _ba) : ba(_ba) {} + Response(const Response& other) : ba(other.ba) {} + Json json() { + return QJsonDocument::fromJson(ba); + } +private: + QByteArray ba; +}; + + +class Requests : public QObject +{ +public: + Requests() + { + manager = new QNetworkAccessManager(); + + QObject::connect(manager, &QNetworkAccessManager::finished, + this, [=](QNetworkReply* reply) + { + if (reply->error()) { + qDebug() << reply->errorString(); + return; + } + + if (continuationMap.count(reply)) + { + Response resp(reply->readAll()); + continuationMap[reply](resp); + } + }); + } + + ~Requests() + { + delete manager; + } + + // sessions? + void get(const std::string& url, const KeyValuePairs& headers, std::function continuation) + { + QNetworkRequest request; + request.setUrl(QUrl(url.c_str())); + auto resp = manager->get(request); + continuationMap[resp] = continuation; + } + +private: + QNetworkAccessManager* manager; + std::unordered_map> continuationMap; +}; + + +class MovieAggregator : public QObject +{ +}; + + +class JustWatch : public MovieAggregator +{ + static std::string api_base_template; +public: + JustWatch(const char* _country = "US")//, bool _use_sessions = true) + { + requests = new Requests; + // self.kwargs = kwargs + country = _country; + //self.kwargs_cinema = [] + setupLocale(); + } + + ~JustWatch() + { + delete requests; + } + + void setupLocale(); + + void searchForItem(std::string query, KeyValuePairs kwargs); + void getProviders(); + void getGenres(); + void getTitle(std::string title_id, std::string content_type = "movie"); + void searchTitleId(std::string query); + void getSeason(std::string season_id); + void getCinemaTimes(std::string title_id, std::string content_type = "movie", KeyValuePairs kwargs = {}); + void getCinemaDetails(KeyValuePairs kwargs); + void getUpcomingCinema(int weeks_offset, bool nationwide_cinema_releases_only = true); + void getCertifications(std::string content_type = "movie"); + void getPersonCetail(std::string person_id); + +private: + Requests* requests; + std::string country; + std::string locale; +}; + + +void JustWatch::setupLocale() +{ + std::string default_locale = "en_AU"; + std::string api_url = api_base_template + "locales/state"; + KeyValuePairs headers = { { "User - Agent", "JustWatch client(github.com / dawoudt / JustWatchAPI)" } }; + requests->get(api_url, headers, [=](Response& resp) + { + std::string str = resp.json().toJson(QJsonDocument::Indented).toStdString(); + qDebug() << str.c_str(); + + locale = default_locale; + auto results = resp.json(); + //QJsonArray arr; + for (auto result : results.array()) + if ((result.toObject()["iso_3166_2"].toString().toStdString() == country) + || (result.toObject()["country"].toString().toStdString() == country)) + locale = result.toObject()["full_locale"].toString().toStdString(); + }); + + // warn = '\nWARN: Unable to locale for {}! Defaulting to en_AU\n' + //sys.stderr.write(warn.format(self.country)) + //return default_locale; +} + + +std::string JustWatch::api_base_template = "http://apis.justwatch.com/content/";// {path}"; + + +class VideoManager : public QObject +{ +public: + VideoManager(); + ~VideoManager() {} + + void getList(); + +private: + JustWatch justWatch; +}; + + +VideoManager::VideoManager() +{ +} + + +void VideoManager::getList() +{ +} VideoList::VideoList(QWidget *parent) : QWidget(parent) @@ -15,12 +178,14 @@ devices->setFocus(); new Text(this, 380+2, 230+2, "Not Implemented", 20, QColor(0,0,0,128)); new Text(this, 380, 230, "Not Implemented", 20); + + manager = new VideoManager; } VideoList::~VideoList() { - + delete manager; } @@ -30,3 +195,264 @@ devices->setFocus(); } + + + +#if 0 + +JustWatch API + + +from datetime import datetime +from datetime import timedelta +import requests +import sys + + +HEADER = { 'User-Agent':'JustWatch client (github.com/dawoudt/JustWatchAPI)' } + + +class JustWatch : + api_base_template = "https://apis.justwatch.com/content/{path}" + + def __init__(self, country = 'AU', use_sessions = True, **kwargs) : + self.kwargs = kwargs + self.country = country + self.kwargs_cinema = [] + self.requests = requests.Session() if use_sessions else requests + self.locale = self.set_locale() + + + def __del__(self) : + ''' Should really use context manager + but this should do without changing functionality. + ''' + if isinstance(self.requests, requests.Session) : + self.requests.close() + + + def set_locale(self) : + warn = '\nWARN: Unable to locale for {}! Defaulting to en_AU\n' + default_locale = 'en_AU' + path = 'locales/state' + api_url = self.api_base_template.format(path = path) + + r = self.requests.get(api_url, headers = HEADER) + try : + r.raise_for_status() + except requests.exceptions.HTTPError : + sys.stderr.write(warn.format(self.country)) + return default_locale + else: +results = r.json() + +for result in results : +if result['iso_3166_2'] == self.country or \ +result['country'] == self.country: + +return result['full_locale'] + +sys.stderr.write(warn.format(self.country)) +return default_locale + +def search_for_item(self, query = None, **kwargs) : + + path = 'titles/{}/popular'.format(self.locale) + api_url = self.api_base_template.format(path = path) + + if kwargs : + self.kwargs = kwargs + if query : + self.kwargs.update({ 'query': query }) + null = None + payload = { + "age_certifications":null, + "content_types" : null, + "presentation_types" : null, + "providers" : null, + "genres" : null, + "languages" : null, + "release_year_from" : null, + "release_year_until" : null, + "monetization_types" : null, + "min_price" : null, + "max_price" : null, + "nationwide_cinema_releases_only" : null, + "scoring_filter_types" : null, + "cinema_release" : null, + "query" : null, + "page" : null, + "page_size" : null, + "timeline_type" : null, + "person_id" : null + } + for key, value in self.kwargs.items() : + if key in payload.keys() : + payload[key] = value + else : + print('{} is not a valid keyword'.format(key)) + r = self.requests.post(api_url, json = payload, headers = HEADER) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_providers(self) : + path = 'providers/locale/{}'.format(self.locale) + api_url = self.api_base_template.format(path = path) + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_genres(self) : + path = 'genres/locale/{}'.format(self.locale) + api_url = self.api_base_template.format(path = path) + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_title(self, title_id, content_type = 'movie') : + path = 'titles/{content_type}/{title_id}/locale/{locale}'.format(content_type = content_type, + title_id = title_id, + locale = self.locale) + + api_url = self.api_base_template.format(path = path) + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def search_title_id(self, query) : + ''' Returns a dictionary of titles returned + from search and their respective ID's + + >> > ... + >> > just_watch.get_title_id('The Matrix') + { + 'The Matrix': 10, ... + } + +''' + +results = self.search_for_item(query) +return { item['id']: item['title'] for item in results['items'] } + + +def get_season(self, season_id) : + + header = HEADER + api_url = 'https://apis.justwatch.com/content/titles/show_season/{}/locale/{}'.format(season_id, self.locale) + r = self.requests.get(api_url, headers = header) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + + def get_cinema_times(self, title_id, content_type = 'movie', **kwargs) : + + if kwargs : + self.kwargs_cinema = kwargs + + null = None + payload = { + "date":null, + "latitude" : null, + "longitude" : null, + "radius" : 20000 + } + for key, value in self.kwargs_cinema.items() : + if key in payload.keys() : + payload[key] = value + else : + print('{} is not a valid keyword'.format(key)) + + + header = HEADER + api_url = 'https://apis.justwatch.com/content/titles/{}/{}/showtimes'.format(content_type, title_id) + r = self.requests.get(api_url, params = payload, headers = header) + + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + + def get_cinema_details(self, **kwargs) : + + if kwargs : + self.kwargs_cinema = kwargs + + null = None + payload = { + "latitude":null, + "longitude" : null, + "radius" : 20000 + } + for key, value in self.kwargs_cinema.items() : + if key in payload.keys() : + payload[key] = value + elif key == 'date' : + #ignore the date value if passed + pass + else: +print('{} is not a valid keyword'.format(key)) + + +header = HEADER +api_url = 'https://apis.justwatch.com/content/cinemas/{}'.format(self.locale) +r = self.requests.get(api_url, params = payload, headers = header) + +r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + +return r.json() + + + +def get_upcoming_cinema(self, weeks_offset, nationwide_cinema_releases_only = True) : + + header = HEADER + payload = { 'nationwide_cinema_releases_only': nationwide_cinema_releases_only, + 'body' : {} } + now_date = datetime.now() + td = timedelta(weeks = weeks_offset) + year_month_day = (now_date + td).isocalendar() + api_url = 'https://apis.justwatch.com/content/titles/movie/upcoming/{}/{}/locale/{}' + api_url = api_url.format(year_month_day[0], year_month_day[1], self.locale) + + #this throws an error if you go too many weeks forward, so return a blank payload if we hit an error + try : + r = self.requests.get(api_url, params = payload, headers = header) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + except: +return { 'page': 0, 'page_size' : 0, 'total_pages' : 1, 'total_results' : 0, 'items' : [] } + +def get_certifications(self, content_type = 'movie') : + + header = HEADER + payload = { 'country': self.country, 'object_type' : content_type } + api_url = 'https://apis.justwatch.com/content/age_certifications' + r = self.requests.get(api_url, params = payload, headers = header) + + # Client should deal with rate - limiting.JustWatch may send a 429 Too Many Requests response. + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + + def get_person_detail(self, person_id) : + path = 'titles/person/{person_id}/locale/{locale}'.format(person_id = person_id, locale = self.locale) + api_url = self.api_base_template.format(path = path) + + r = self.requests.get(api_url, headers = HEADER) + r.raise_for_status() # Raises requests.exceptions.HTTPError if r.status_code != 200 + + return r.json() + +#endif diff --git a/applications/Photoframe/src/videolist.h b/applications/Photoframe/src/videolist.h index 2f77bf7..e46e8b0 100755 --- a/applications/Photoframe/src/videolist.h +++ b/applications/Photoframe/src/videolist.h @@ -3,6 +3,7 @@ #include +class VideoManager; class DeviceList; @@ -18,6 +19,7 @@ void switchFocus(); private: DeviceList *devices; + VideoManager* manager; };