Commit 7a568679 authored by Camilo Higuita's avatar Camilo Higuita

multiple fixes and close menus after action is trigerred, and group babetable with sections

parent aaf7362a
......@@ -9,22 +9,24 @@ QT += qml
QT += quickcontrols2
android: QT += androidextras
TARGET = babe
TEMPLATE = app
CONFIG += c++11
unix:linux:!android:
{
include(kde/kde.pri)
}
linux:unix:!android {
include(kde/kde.pri)
android:
{
message(Building for helpers for Android)
} else:android {
message(Building helpers for Android)
include(android/android.pri)
include(android-openssl.pri)
include(3rdparty/kirigami/kirigami.pri)
} else {
message("Unknown configuration")
}
......
......@@ -66,6 +66,56 @@
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
<service android:process=":qt" android:name=".MyService">
<!-- android:process=":qt" is needed to force the service to run on a separate process than the Activity -->
<!-- Application arguments -->
<meta-data android:name="android.app.arguments" android:value="-service"/>
<!-- Application arguments -->
<!-- If you are using the same application (.so file) for activity and also for service, then you
need to use *android.app.arguments* to pass some arguments to your service in order to know which
one is which.
-->
<!-- Application to launch -->
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<!-- Application to launch -->
<!-- Ministro -->
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Ministro -->
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Deploy Qt libs as part of package -->
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Run with local libs -->
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Background running -->
<meta-data android:name="android.app.background_running" android:value="true"/>
<!-- Background running -->
</service>
</application>
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/>
......
android {
QT += androidextras
HEADERS += \
......@@ -11,7 +13,10 @@ SOURCES += \
DISTFILES += \
$$PWD/src/SendIntent.java \
$$PWD/src/NotificationClient.java
$$PWD/src/NotificationClient.java \
$$PWD/src/MyService.java
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/src
}
......@@ -43,11 +43,27 @@ void NotificationClient::updateAndroidNotification()
{
#if defined(Q_OS_ANDROID)
QAndroidJniObject javaNotification = QAndroidJniObject::fromString(m_notification);
QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
"notify",
"(Ljava/lang/String;)V",
javaNotification.object<jstring>());
QAndroidJniEnvironment _env;
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid
if (_env->ExceptionCheck()) {
_env->ExceptionClear();
throw InterfaceConnFailedException();
}
if ( activity.isValid() )
{
QAndroidJniObject::callStaticMethod<void>("com/example/android/tools/NotificationClient",
"notify",
"(Landroid/content/Context;Ljava/lang/String;)V",
QtAndroid::androidContext().object(),
QAndroidJniObject::fromString(m_notification).object<jstring>());
if (_env->ExceptionCheck()) {
_env->ExceptionClear();
throw InterfaceConnFailedException();
}
}else
throw InterfaceConnFailedException();
#endif
}
package com.kdab.training;
import org.qtproject.qt5.android.bindings.QtService;
import android.content.Intent;
import android.content.Context;
public class MyService extends QtService
{
public static void startMyService(Context ctx)
{
ctx.startService(new Intent(ctx, MyService.class));
}
}
package org.qtproject.example.notification;
package com.example.android.tools;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.app.PendingIntent ;
public class NotificationClient extends org.qtproject.qt5.android.bindings.QtActivity
{
private static NotificationManager m_notificationManager;
private static Notification.Builder m_builder;
private static NotificationClient m_instance;
import android.content.Context;
public NotificationClient()
{
m_instance = this;
}
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.app.NotificationCompat;
import org.qtproject.qt5.android.QtNative;
public static void notify(String s)
public class NotificationClient
{
public static void notify(Context context, String s)
{
if (m_notificationManager == null) {
m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE);
m_builder = new Notification.Builder(m_instance);
m_builder.setContentTitle("A message from Qt!");
}
m_builder.setContentText(s);
m_notificationManager.notify(1, m_builder.build());
Intent intent = new Intent(context, NotificationClient.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);
// Add as notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
// notificationId is a unique int for each notification that you must define
notificationManager.notify(100, mBuilder.build());
}
}
......@@ -19,24 +19,46 @@ public class SendIntent
context.startActivity(Intent.createChooser(sendIntent, text));
}
public static void sendUrl(Activity context, String text)
{
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
sendIntent.setType("text/plain");
context.startActivity(Intent.createChooser(sendIntent, text));
}
public static void sendUrl(Activity context, String text)
{
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
sendIntent.setType("text/plain");
context.startActivity(Intent.createChooser(sendIntent, text));
}
public static void sendTrack(Activity context, String url)
{
File file = new File(url);
System.out.println(file.exists());
Uri uri = Uri.fromFile(file);
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
sendIntent.setType("audio/mp3");
context.startActivity(Intent.createChooser(sendIntent, "Share track"));
}
public static void openFile(Activity context, String url)
{
File file = new File(url);
Uri uri = Uri.fromFile(file);
String mime = context.getContentResolver().getType(uri);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setDataAndType(uri, mime);
context.startActivity(Intent.createChooser(intent, "Open folder"));
// Intent sendIntent = new Intent();
// sendIntent.setAction(Intent.ACTION_VIEW);
// sendIntent.setDataAndType(uri, mime);
// sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(sendIntent);
}
public static void sendTrack(Activity context, String url)
{
File file = new File(url);
System.out.println(file.exists());
Uri uri = Uri.fromFile(file);
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
sendIntent.setType("audio/mp3");
context.startActivity(Intent.createChooser(sendIntent, "Share track"));
}
}
......@@ -68,8 +68,8 @@ Babe::Babe(QObject *parent) : CollectionDB(parent)
{
emit this->skipTrack();
});
//#elif defined (Q_OS_ANDROID)
// this->nof = new NotificationClient(this);
#elif defined (Q_OS_ANDROID)
this->nof = new NotificationClient(this);
#endif
}
......@@ -320,6 +320,33 @@ void Babe::sendTrack(const QString &url)
}
void Babe::openFile(const QString &url)
{
#if defined(Q_OS_ANDROID)
bDebug::Instance()->msg("Opening track "+ url);
QAndroidJniEnvironment _env;
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid
if (_env->ExceptionCheck()) {
_env->ExceptionClear();
throw InterfaceConnFailedException();
}
if ( activity.isValid() )
{
QAndroidJniObject::callStaticMethod<void>("com/example/android/tools/SendIntent",
"openFile",
"(Landroid/app/Activity;Ljava/lang/String;)V",
activity.object<jobject>(),
QAndroidJniObject::fromString(url).object<jstring>());
if (_env->ExceptionCheck()) {
_env->ExceptionClear();
throw InterfaceConnFailedException();
}
}else
throw InterfaceConnFailedException();
#endif
}
void Babe::scanDir(const QString &url)
{
emit this->settings->collectionPathChanged({url});
......
......@@ -121,6 +121,7 @@ public:
/*ANDROID*/
Q_INVOKABLE static void sendText(const QString &text);
Q_INVOKABLE static void sendTrack(const QString &url);
Q_INVOKABLE static void openFile(const QString &url);
Q_INVOKABLE static void androidStatusBarColor(const QString &color);
......
......@@ -13,7 +13,7 @@ var GET = {
tracksWhere_ : "select t.*, al.artwork from tracks t inner join albums al on al.album = t.album and al.artist = t.artist where %1",
mostPlayedTracks : "select t.*, al.artwork from tracks t inner join albums al on t.album = al.album and t.artist = al.artist WHERE al.played > 0 ORDER BY played desc LIMIT 100",
mostPlayedTracks : "select t.*, al.artwork from tracks t inner join albums al on t.album = al.album and t.artist = al.artist WHERE t.played > 0 ORDER BY played desc LIMIT 100",
favoriteTracks : "select t.*, al.artwork from tracks t inner join albums al on t.album = al.album and t.artist = al.artist where stars > 0 order by stars desc limit 100",
recentTracks: "select t.* , al.artwork from tracks t inner join albums al on t.album = al.album and t.artist = al.artist order by strftime(\"%s\", t.addDate) desc LIMIT 100",
babedTracks: "select t.* , al.artwork from tracks t inner join albums al on t.album = al.album and t.artist = al.artist where t.babe = 1",
......
......@@ -400,7 +400,7 @@ bool CollectionDB::albumTrack(const DB &track, const QString &value)
bool CollectionDB::playedTrack(const QString &url, const int &increment)
{
auto queryTxt = QString("UPDATE %1 SET %2 = %2 + %3 WHERE %4 = \"%5\"").arg(TABLEMAP[TABLE::TRACKS],
KEYMAP[KEY::PLAYED], QString::number(increment), KEYMAP[KEY::URL],url);
KEYMAP[KEY::PLAYED], QString::number(increment), KEYMAP[KEY::URL], url);
auto query = this->getQuery(queryTxt);
......@@ -830,8 +830,7 @@ bool CollectionDB::removeTrack(const QString &path)
QSqlQuery CollectionDB::getQuery(const QString &queryTxt)
{
QSqlQuery query(queryTxt, this->m_db);
return query;
return QSqlQuery(queryTxt, this->m_db);
}
bool CollectionDB::removeSource(const QString &path)
......
......@@ -51,7 +51,7 @@ public:
Q_INVOKABLE QString trackColorTag(const QString &path);
bool lyricsTrack(const BAE::DB &track, const QString &value);
bool playedTrack(const QString &url, const int &increment = 1);
Q_INVOKABLE bool playedTrack(const QString &url, const int &increment = 1);
bool wikiTrack(const BAE::DB &track, const QString &value);
bool tagsTrack(const BAE::DB &track, const QString &value, const QString &context);
......@@ -87,8 +87,8 @@ public:
QStringList getTrackTags(const QString &path);
Q_INVOKABLE int getTrackStars(const QString &path);
// QStringList getArtistTags(const QString &artist);
// QStringList getAlbumTags(const QString &album, const QString &artist);
// QStringList getArtistTags(const QString &artist);
// QStringList getAlbumTags(const QString &album, const QString &artist);
QStringList getArtistAlbums(const QString &artist);
Q_INVOKABLE QStringList getPlaylists();
......
linux:unix:!android {
linux:unix:!android
{
message(Building for Linux)
QT += dbus
QT += KConfigCore
......@@ -7,16 +8,10 @@ linux:unix:!android {
QT += KI18n
HEADERS += \ kde/notify.h \
kde/mpris2.h
kde/mpris2.h \
kde/kdeconnect.h
SOURCES += kde/notify.cpp \
kde/mpris2.cpp
kde/mpris2.cpp \
kde/kdeconnect.cpp
}
HEADERS += \
$$PWD/kdeconnect.h
SOURCES += \
$$PWD/kdeconnect.cpp
......@@ -216,8 +216,13 @@ Kirigami.ApplicationWindow
onPos: progressBar.value = pos
onTiming: progressTimeLabel = time
onDurationChanged: durationTimeLabel = time
onFinished: Player.nextTrack()
onIsPlaying: isPlaying = playing
onFinished:
{
bae.playedTrack(currentTrack.url)
Player.nextTrack()
}
onIsPlaying: isPlaying = playing
}
Connections
......@@ -302,7 +307,7 @@ Kirigami.ApplicationWindow
height: visible ? headerHeight : 0
width: root.width
visible: true
focus: true
FastBlur
{
anchors.fill: parent
......@@ -351,6 +356,7 @@ Kirigami.ApplicationWindow
to: 1000
value: 0
spacing: 0
focus: true
onMoved: player.seek(player.duration() / 1000 * value);
......@@ -366,7 +372,7 @@ Kirigami.ApplicationWindow
Kirigami.Separator
{
visible: !isMobile
Rectangle
{
anchors.fill: parent
......@@ -446,14 +452,12 @@ Kirigami.ApplicationWindow
loops: Animation.Infinite
running: miniArtwork.visible && isPlaying
}
// height: headerHeight
// width: miniArtwork.visible ? headerHeight : 0
Image
{
id: miniArtwork
visible: ((!pageStack.wideMode && pageStack.currentIndex !== 0) || !mainPlaylist.cover.visible) && !mainlistEmpty
focus: true
height: miniArtSize
width: miniArtSize
// anchors.left: parent.left
......@@ -479,8 +483,6 @@ Kirigami.ApplicationWindow
}
}
layer.enabled: true
layer.effect: OpacityMask
{
......@@ -578,7 +580,7 @@ Kirigami.ApplicationWindow
iconName: "media-skip-forward"
onClicked: Player.nextTrack()
// onPressAndHold: Player.playAt(Player.shuffle())
onPressAndHold: Player.playAt(Player.shuffle())
}
BabeButton
......
......@@ -85,6 +85,7 @@ void Player::update()
}
emit this->isPlaying(this->player->state() == QMediaPlayer::PlayingState ? true : false);
if(this->player->state() == QMediaPlayer::StoppedState)
if(this->player->state() == QMediaPlayer::StoppedState)
emit this->finished();
}
......@@ -8,4 +8,34 @@ function rootHeight()
return root.height;
}
function setStars(stars)
{
switch (stars)
{
case "0":
case 0:
return " ";
case "1":
case 1:
return "\uf4CE";
case "2":
case 2:
return "\uf4CE \uf4CE";
case "3":
case 3:
return "\uf4CE \uf4CE \uf4CE";
case "4":
case 4:
return "\uf4CE \uf4CE \uf4CE \uf4CE";
case "5":
case 5:
return "\uf4CE \uf4CE \uf4CE \uf4CE \uf4CE";
default: return "error";
}
}
......@@ -6,16 +6,20 @@ ItemDelegate
{
id: listItem
width: parent.width
height: rowHeightAlt
property bool isSection : false
property bool boldLabel : false
property alias label: labelTxt.text
property alias fontFamily: labelTxt.font.family
property string textColor: ListView.isCurrentItem ? highlightTextColor : foregroundColor
Rectangle
{
anchors.fill: parent
color: index % 2 === 0 ? midColor : "transparent"
color: isSection ? midLightColor : (index % 2 === 0 ? midColor : "transparent")
opacity: 0.3
}
......@@ -38,6 +42,8 @@ ItemDelegate
text: labelTxt.text
elide: Text.ElideRight
color: textColor
font.bold: boldLabel
font.weight : boldLabel ? Font.Bold : Font.Normal
}
}
}
......@@ -13,7 +13,7 @@ Item
property alias currentIndex : babeList.currentIndex
property alias currentItem : babeList.currentItem
property alias holder : holder
property alias section : babeList.section
property alias headerBarRight : headerBarActionsRight.children
property alias headerBarLeft : headerBarActionsLeft.children
......@@ -58,6 +58,8 @@ Item
Kirigami.Separator
{
visible: !isMobile
Rectangle
{
anchors.fill: parent
......
......@@ -21,19 +21,26 @@ BabeMenu
BabeMenuItem
{
text: "Queue list"
onTriggered: queueListClicked()
onTriggered:
{
queueListClicked()
close()
}
}
BabeMenuItem
{
text: "Save list to..."
onTriggered: saveListClicked()
onTriggered:
{
saveListClicked()
close()
}
}
BabeMenuItem
{
text: "Send list to..."
}
Kirigami.Separator{ width: parent.width; height: 1}
......@@ -41,7 +48,7 @@ BabeMenu
BabeMenuItem
{
text: "Visible info..."
onTriggered: {}
onTriggered: {close()}
}
Kirigami.Separator{ width: parent.width; height: 1}
......@@ -49,7 +56,7 @@ BabeMenu
BabeMenuItem
{
text: "Sort..."
onTriggered: {}
onTriggered: {close()}
}
}
......
......@@ -3,6 +3,7 @@ import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import "../../view_models"
import QtGraphicalEffects 1.0
import "../../utils/Help.js" as H
ItemDelegate
{
......@@ -320,7 +321,7 @@ ItemDelegate
// Layout.columnSpan: trackRatingVisible && sameAlbum ? 4 : 3
horizontalAlignment: Qt.AlignRight
verticalAlignment: Qt.AlignVCenter
text: setStars(stars)
text: H.setStars(stars)
font.bold: false
elide: Text.ElideRight
font.pointSize: fontSizes.small
......@@ -344,37 +345,5 @@ ItemDelegate
// onClicked: rightClicked()
// }
// }
}
function setStars(stars)
{
switch (stars)
{
case "0":
case 0:
return " ";
case "1":
case 1:
return "\uf4CE";
case "2":
case 2:
return "\uf4CE \uf4CE";
case "3":
case 3:
return "\uf4CE \uf4CE \uf4CE";
case "4":
case 4:
return "\uf4CE \uf4CE \uf4CE \uf4CE";
case "5":
case 5:
return "\uf4CE \uf4CE \uf4CE \uf4CE \uf4CE";
default: return "error";
}
}
}
}
......@@ -6,6 +6,7 @@ import "../../view_models/BabeMenu"
import "../../utils"
import ".."
import "../../utils/Player.js" as Player
import "../../utils/Help.js" as H
BabeMenu
{
......@@ -28,12 +29,11 @@ BabeMenu
rate = rank
if(bae.rateTrack(list.model.get(list.currentIndex).url, rate))
{
list.currentItem.trackRating.text = list.currentItem.setStars(rate)
list.currentItem.trackRating.text = H.setStars(rate)
list.model.get(list.currentIndex).stars = rate
}
if(!root.isMobile)
dismiss()
else close()
close()
}
function moodIt(color)
......@@ -43,9 +43,8 @@ BabeMenu
list.currentItem.trackMood = color
list.model.get(list.currentIndex).art = color
}
if(!root.isMobile)
dismiss()
else close()
close()
}
function babeIt(index)
......@@ -129,13 +128,21 @@ BabeMenu
BabeMenuItem
{
text: babe == false ? "Babe it" : "UnBabe it"
onTriggered: babeIt(list.currentIndex)
onTriggered:
{
babeIt(list.currentIndex)
close()
}
}
BabeMenuItem
{
text: "Queue"
onTriggered: queueIt(list.currentIndex)
onTriggered:
{
queueIt(list.currentIndex)