diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index e38cfd0ab..1049103b0 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -736,6 +736,7 @@ Query::socialActionDescription( const QString& action, DescriptionMode mode ) co } } + QDateTime earliestTimestamp = QDateTime::currentDateTime(); actionSources.clear(); int loveCounter = 0; foreach ( const Tomahawk::SocialAction& sa, socialActions ) @@ -765,6 +766,10 @@ Query::socialActionDescription( const QString& action, DescriptionMode mode ) co } else desc += "" + sa.source->friendlyName() + ""; + + QDateTime saTimestamp = QDateTime::fromTime_t( sa.timestamp.toInt() ); + if ( saTimestamp < earliestTimestamp && saTimestamp.toTime_t() > 0 ) + earliestTimestamp = saTimestamp; } } if ( loveCounter > 0 ) @@ -775,7 +780,12 @@ Query::socialActionDescription( const QString& action, DescriptionMode mode ) co if ( mode == Short ) desc = "" + tr( "%n people", "", loveCounter ) + ""; - desc += " " + tr( "loved this track" ); //FIXME: more action descs required + //FIXME: more action descs required + if ( action == "Love" ) + desc += " " + tr( "loved this track" ); + else if ( action == "Inbox" ) + desc += " " + tr( "sent you this track %1" ) + .arg( TomahawkUtils::ageToString( earliestTimestamp, true ) ); } return desc; diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index ee2eb3fcb..a616da83e 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -443,7 +443,7 @@ ViewManager::showInboxPage() TrackView* inboxView = new TrackView( m_widget ); PlaylistLargeItemDelegate* delegate = - new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::/*Inbox*/LovedTracks, + new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::Inbox, inboxView, inboxView->proxyModel() ); connect( delegate, SIGNAL( updateIndex( QModelIndex ) ), diff --git a/src/libtomahawk/database/DatabaseCommand_ShareTrack.cpp b/src/libtomahawk/database/DatabaseCommand_ShareTrack.cpp index 90d48806f..291558a7d 100644 --- a/src/libtomahawk/database/DatabaseCommand_ShareTrack.cpp +++ b/src/libtomahawk/database/DatabaseCommand_ShareTrack.cpp @@ -90,6 +90,16 @@ DatabaseCommand_ShareTrack::postCommitHook() if ( m_query.isNull() ) return; + Tomahawk::SocialAction action; + action.action = "Inbox"; + action.source = source(); + action.value = true; //unlistened + action.timestamp = timestamp(); + + QList< Tomahawk::SocialAction > actions; + actions << action; + m_query->setAllSocialActions( actions ); + QMetaObject::invokeMethod( ViewManager::instance()->inboxModel(), "insertQuery", Qt::QueuedConnection, diff --git a/src/libtomahawk/playlist/InboxModel.cpp b/src/libtomahawk/playlist/InboxModel.cpp index 17f1af1a5..b236186cb 100644 --- a/src/libtomahawk/playlist/InboxModel.cpp +++ b/src/libtomahawk/playlist/InboxModel.cpp @@ -20,12 +20,19 @@ #include "database/Database.h" #include "database/DatabaseCommand_GenericSelect.h" +#include "SourceList.h" +#include "utils/Logger.h" +#include "utils/Closure.h" InboxModel::InboxModel( QObject* parent ) : PlaylistModel( parent ) { - loadTracks(); + if ( SourceList::instance()->isReady() ) + loadTracks(); + else + NewClosure( SourceList::instance(), SIGNAL( ready() ), + this, SLOT( loadTracks() ) ); } @@ -33,6 +40,92 @@ InboxModel::~InboxModel() {} +QList +InboxModel::mergeSocialActions( QList first, QList second) +{ + foreach ( Tomahawk::SocialAction sa, second ) + { + if ( sa.action != "Inbox" ) + { + first.append( sa ); + continue; + } + + bool contains = false; + for ( int i = 0; i < first.count(); ++i ) + { + Tomahawk::SocialAction &sb = first[ i ]; + if ( sa.source == sb.source ) + { + sb.timestamp = qMax( sa.timestamp.toInt(), sb.timestamp.toInt() ); + sb.value = sa.value.toBool() && sb.value.toBool(); + contains = true; + break; + } + } + if ( !contains ) + first.append( sa ); + } + return first; +} + + +void +InboxModel::insertEntries( const QList< Tomahawk::plentry_ptr >& entries, int row ) +{ + QList< Tomahawk::plentry_ptr > toInsert; + for ( QList< Tomahawk::plentry_ptr >::const_iterator it = entries.constBegin(); + it != entries.constEnd(); ++it ) + { + Tomahawk::plentry_ptr entry = *it; + bool gotDupe = false; + for ( QList< Tomahawk::plentry_ptr >::iterator jt = toInsert.begin(); + jt != toInsert.end(); ++jt ) + { + Tomahawk::plentry_ptr existingEntry = *jt; + if ( entry->query()->equals( existingEntry->query(), true /*ignoreCase*/) ) + { + //We got a dupe, let's merge the social actions + existingEntry->query()->setAllSocialActions( mergeSocialActions( existingEntry->query()->allSocialActions(), + entry->query()->allSocialActions() ) ); + gotDupe = true; + break; + } + } + if ( !gotDupe ) + toInsert.append( entry ); + } + + foreach ( Tomahawk::plentry_ptr plEntry, playlistEntries() ) + { + for ( int i = 0; i < toInsert.count(); ) + { + if ( plEntry->query()->equals( toInsert.at( i )->query(), true ) ) + { + plEntry->query()->setAllSocialActions( mergeSocialActions( plEntry->query()->allSocialActions(), + toInsert.at( i )->query()->allSocialActions() ) ); + toInsert.removeAt( i ); + + dataChanged( index( playlistEntries().indexOf( plEntry ), 0, QModelIndex() ), + index( playlistEntries().indexOf( plEntry ), columnCount() -1, QModelIndex() ) ); + } + else + ++i; + } + } + changed(); + + PlaylistModel::insertEntries( toInsert, row ); +} + + +void +InboxModel::clear() +{ + PlaylistModel::clear(); +} + + void InboxModel::loadTracks() { @@ -60,6 +153,23 @@ InboxModel::tracksLoaded( QList< Tomahawk::query_ptr > newTracks ) foreach ( const Tomahawk::plentry_ptr ple, playlistEntries() ) tracks << ple->query(); + foreach ( Tomahawk::query_ptr newQuery, newTracks ) + { + QVariantList extraData = newQuery->property( "data" ).toList(); + + Tomahawk::SocialAction action; + action.action = "Inbox"; + action.source = SourceList::instance()->get( extraData.at( 0 ).toInt() ); + action.value = extraData.at( 1 ).toBool(); //unlistened + action.timestamp = extraData.at( 2 ).toUInt(); + + QList< Tomahawk::SocialAction > actions; + actions << action; + newQuery->setAllSocialActions( actions ); + + newQuery->setProperty( "data", QVariant() ); //clear + } + bool changed = false; QList< Tomahawk::query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, newTracks, changed ); @@ -71,3 +181,4 @@ InboxModel::tracksLoaded( QList< Tomahawk::query_ptr > newTracks ) appendEntries( el ); } } + diff --git a/src/libtomahawk/playlist/InboxModel.h b/src/libtomahawk/playlist/InboxModel.h index a44275787..4ae757725 100644 --- a/src/libtomahawk/playlist/InboxModel.h +++ b/src/libtomahawk/playlist/InboxModel.h @@ -23,6 +23,7 @@ #include "Typedefs.h" #include "DllMacro.h" + class DLLEXPORT InboxModel : public PlaylistModel { Q_OBJECT @@ -30,13 +31,24 @@ public: explicit InboxModel( QObject* parent = 0 ); virtual ~InboxModel(); +public slots: + /** + * Reimplemented from PlaylistModel, all track insertions/appends go through this method. + * On top of PlaylistModel functionality, adds deduplication/grouping of equivalent tracks + * sent from different sources. + */ + virtual void insertEntries( const QList< Tomahawk::plentry_ptr >& entries, int row = 0 ); + + virtual void clear(); + private slots: void loadTracks(); void tracksLoaded( QList< Tomahawk::query_ptr > ); private: - QTimer* m_smoothingTimer; + static QList< Tomahawk::SocialAction > mergeSocialActions( QList< Tomahawk::SocialAction > first, + QList< Tomahawk::SocialAction > second ); }; #endif // INBOXMODEL_H diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp index 30d248fcf..a627c00ab 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -144,6 +144,8 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& if ( m_mode == LovedTracks ) lowerText = item->query()->socialActionDescription( "Love", Query::Detailed ); + if ( m_mode == Inbox ) + lowerText = item->query()->socialActionDescription( "Inbox", Query::Detailed ); painter->save(); {