mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-03-20 07:49:42 +01:00
* Added cover() method to Query.
This commit is contained in:
parent
60d11db923
commit
18c16959ed
@ -220,12 +220,12 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
if ( !m_currentTrack.isNull() )
|
||||
{
|
||||
disconnect( m_currentTrack->album().data(), SIGNAL( updated() ), this, SLOT( onAlbumCoverUpdated() ) );
|
||||
disconnect( m_currentTrack->toQuery().data(), SIGNAL( updated() ), this, SLOT( onCoverUpdated() ) );
|
||||
disconnect( m_currentTrack->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( onSocialActionsLoaded() ) );
|
||||
}
|
||||
|
||||
m_currentTrack = result;
|
||||
connect( m_currentTrack->album().data(), SIGNAL( updated() ), SLOT( onAlbumCoverUpdated() ) );
|
||||
connect( m_currentTrack->toQuery().data(), SIGNAL( updated() ), SLOT( onCoverUpdated() ) );
|
||||
connect( m_currentTrack->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) );
|
||||
|
||||
ui->artistTrackLabel->setResult( result );
|
||||
@ -243,29 +243,29 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
ui->loveButton->setEnabled( true );
|
||||
ui->loveButton->setVisible( true );
|
||||
|
||||
setAlbumCover();
|
||||
setCover();
|
||||
setSocialActions();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::onAlbumCoverUpdated()
|
||||
AudioControls::onCoverUpdated()
|
||||
{
|
||||
Album* album = qobject_cast< Album* >( sender() );
|
||||
if ( !album || album != m_currentTrack->album().data() )
|
||||
Query* query = qobject_cast< Query* >( sender() );
|
||||
if ( !query || query != m_currentTrack->toQuery().data() )
|
||||
return;
|
||||
|
||||
setAlbumCover();
|
||||
setCover();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::setAlbumCover()
|
||||
AudioControls::setCover()
|
||||
{
|
||||
if ( !m_currentTrack->album()->cover( ui->coverImage->size() ).isNull() )
|
||||
if ( !m_currentTrack->toQuery()->cover( ui->coverImage->size() ).isNull() )
|
||||
{
|
||||
QPixmap cover;
|
||||
cover = m_currentTrack->album()->cover( ui->coverImage->size() );
|
||||
cover = m_currentTrack->toQuery()->cover( ui->coverImage->size() );
|
||||
ui->coverImage->setPixmap( cover );
|
||||
}
|
||||
else
|
||||
@ -277,16 +277,10 @@ void
|
||||
AudioControls::onSocialActionsLoaded()
|
||||
{
|
||||
Query* query = qobject_cast< Query* >( sender() );
|
||||
if ( !query )
|
||||
if ( !query || query != m_currentTrack->toQuery().data() )
|
||||
return;
|
||||
|
||||
query_ptr currentQuery = m_currentTrack->toQuery();
|
||||
if ( query->artist() == currentQuery->artist() &&
|
||||
query->track() == currentQuery->track() &&
|
||||
query->album() == currentQuery->album() )
|
||||
{
|
||||
setSocialActions();
|
||||
}
|
||||
setSocialActions();
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,14 +79,13 @@ private slots:
|
||||
void onTrackClicked();
|
||||
void onLoveButtonClicked( bool );
|
||||
|
||||
void onAlbumCoverUpdated();
|
||||
|
||||
void droppedTracks( QList<Tomahawk::query_ptr> );
|
||||
|
||||
void onCoverUpdated();
|
||||
void onSocialActionsLoaded();
|
||||
|
||||
private:
|
||||
void setAlbumCover();
|
||||
void setCover();
|
||||
void setSocialActions();
|
||||
|
||||
Ui::AudioControls *ui;
|
||||
|
@ -80,6 +80,10 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr&
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( finished( QString ) ),
|
||||
SLOT( infoSystemFinished( QString ) ) );
|
||||
}
|
||||
|
||||
|
||||
@ -109,6 +113,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
|
||||
{
|
||||
if ( !forceLoad )
|
||||
return QPixmap();
|
||||
|
||||
m_uuid = uuid();
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
@ -160,7 +165,6 @@ Album::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
|
||||
return;
|
||||
}
|
||||
|
||||
m_infoLoaded = true;
|
||||
if ( !output.isNull() && output.isValid() )
|
||||
{
|
||||
QVariantMap returnedData = output.value< QVariantMap >();
|
||||
@ -170,7 +174,18 @@ Album::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
|
||||
m_coverBuffer = ba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Album::infoSystemFinished( QString target )
|
||||
{
|
||||
Q_UNUSED( target );
|
||||
|
||||
if ( target != m_uuid )
|
||||
return;
|
||||
|
||||
m_infoLoaded = true;
|
||||
emit updated();
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ private slots:
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks );
|
||||
|
||||
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
void infoSystemFinished( QString target );
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( Album )
|
||||
|
@ -81,6 +81,10 @@ Artist::Artist( unsigned int id, const QString& name )
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( finished( QString ) ),
|
||||
SLOT( infoSystemFinished( QString ) ) );
|
||||
}
|
||||
|
||||
|
||||
@ -152,7 +156,6 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
|
||||
return;
|
||||
}
|
||||
|
||||
m_infoLoaded = true;
|
||||
if ( !output.isNull() && output.isValid() )
|
||||
{
|
||||
QVariantMap returnedData = output.value< QVariantMap >();
|
||||
@ -162,7 +165,18 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
|
||||
m_coverBuffer = ba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Artist::infoSystemFinished( QString target )
|
||||
{
|
||||
Q_UNUSED( target );
|
||||
|
||||
if ( target != m_uuid )
|
||||
return;
|
||||
|
||||
m_infoLoaded = true;
|
||||
emit updated();
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,7 @@ private slots:
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks );
|
||||
|
||||
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
void infoSystemFinished( QString target );
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( Artist )
|
||||
|
@ -36,9 +36,6 @@
|
||||
#include "utils/tomahawkutilsgui.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#define PLAYING_ICON QString( RESPATH "images/now-playing-speaker.png" )
|
||||
#define ARROW_ICON QString( RESPATH "images/info.png" )
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
@ -47,16 +44,11 @@ PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel*
|
||||
, m_view( parent )
|
||||
, m_model( proxy )
|
||||
{
|
||||
m_nowPlayingIcon = QPixmap( PLAYING_ICON );
|
||||
m_arrowIcon = QPixmap( ARROW_ICON );
|
||||
|
||||
m_topOption = QTextOption( Qt::AlignTop );
|
||||
m_topOption.setWrapMode( QTextOption::NoWrap );
|
||||
|
||||
m_bottomOption = QTextOption( Qt::AlignBottom );
|
||||
m_bottomOption.setWrapMode( QTextOption::NoWrap );
|
||||
|
||||
m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) );
|
||||
}
|
||||
|
||||
|
||||
@ -140,6 +132,7 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
|
||||
break;
|
||||
case TrackModel::ShortWithAvatars:
|
||||
paintShort( painter, option, index, true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,16 +181,8 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem&
|
||||
lowerText = QString( tr( "played %1 by you" ) ).arg( playtime );
|
||||
else
|
||||
lowerText = QString( tr( "played %1 by %2" ) ).arg( playtime ).arg( source->friendlyName() );
|
||||
|
||||
if ( useAvatars )
|
||||
pixmap = source->avatar( Source::FancyStyle );
|
||||
}
|
||||
|
||||
if ( pixmap.isNull() && !useAvatars )
|
||||
pixmap = QPixmap( RESPATH "images/track-placeholder.png" );
|
||||
else if ( pixmap.isNull() && useAvatars )
|
||||
pixmap = m_defaultAvatar;
|
||||
|
||||
painter->save();
|
||||
{
|
||||
QRect r = opt.rect.adjusted( 3, 6, 0, -6 );
|
||||
@ -205,27 +190,31 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem&
|
||||
// Paint Now Playing Speaker Icon
|
||||
if ( item->isPlaying() )
|
||||
{
|
||||
r.adjust( 0, 0, 0, 0 );
|
||||
QRect npr = r.adjusted( 3, r.height() / 2 - m_nowPlayingIcon.height() / 2, 18 - r.width(), -r.height() / 2 + m_nowPlayingIcon.height() / 2 );
|
||||
painter->drawPixmap( npr, m_nowPlayingIcon );
|
||||
QPixmap nowPlayingIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker );
|
||||
QRect npr = r.adjusted( 3, r.height() / 2 - nowPlayingIcon.height() / 2, 18 - r.width(), -r.height() / 2 + nowPlayingIcon.height() / 2 );
|
||||
nowPlayingIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker, TomahawkUtils::Original, npr.size() );
|
||||
painter->drawPixmap( npr, nowPlayingIcon );
|
||||
r.adjust( 22, 0, 0, 0 );
|
||||
}
|
||||
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
|
||||
QRect ir = r.adjusted( 4, 0, -option.rect.width() + option.rect.height() - 8 + r.left(), 0 );
|
||||
|
||||
QPixmap scover;
|
||||
if ( m_cache.contains( pixmap.cacheKey() ) )
|
||||
{
|
||||
scover = m_cache.value( pixmap.cacheKey() );
|
||||
}
|
||||
|
||||
if ( useAvatars )
|
||||
pixmap = source->avatar( Source::FancyStyle, ir.size() );
|
||||
else
|
||||
pixmap = item->query()->cover( ir.size() );
|
||||
|
||||
if ( pixmap.isNull() )
|
||||
{
|
||||
scover = pixmap.scaled( ir.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_cache.insert( pixmap.cacheKey(), scover );
|
||||
if ( !useAvatars )
|
||||
pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultTrackImage, TomahawkUtils::ScaledCover, ir.size() );
|
||||
else
|
||||
pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultSourceAvatar, TomahawkUtils::AvatarInFrame, ir.size() );
|
||||
}
|
||||
painter->drawPixmap( ir, scover );
|
||||
|
||||
painter->drawPixmap( ir, pixmap );
|
||||
|
||||
QFont boldFont = opt.font;
|
||||
boldFont.setBold( true );
|
||||
@ -263,9 +252,8 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
opt.rect.setWidth( opt.rect.width() - 16 );
|
||||
QRect arrowRect( opt.rect.x() + opt.rect.width(), opt.rect.y() + 1, opt.rect.height() - 2, opt.rect.height() - 2 );
|
||||
|
||||
if ( m_arrowIcon.height() != arrowRect.height() )
|
||||
m_arrowIcon = m_arrowIcon.scaled( arrowRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
painter->drawPixmap( arrowRect, m_arrowIcon );
|
||||
QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, arrowRect.size() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
}
|
||||
|
||||
painter->save();
|
||||
@ -300,7 +288,7 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
if ( m_view->header()->visualIndex( index.column() ) == 0 )
|
||||
{
|
||||
r.adjust( 0, 0, 0, -3 );
|
||||
painter->drawPixmap( r.adjusted( 3, 1, 18 - r.width(), 1 ), m_nowPlayingIcon );
|
||||
painter->drawPixmap( r.adjusted( 3, 1, 18 - r.width(), 1 ), TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker ) );
|
||||
r.adjust( 25, 0, 0, 3 );
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,6 @@ public:
|
||||
|
||||
void updateRowSize( const QModelIndex& index );
|
||||
|
||||
public slots:
|
||||
void setRemovalProgress( unsigned int progress ) { m_removalProgress = progress; }
|
||||
|
||||
protected:
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
@ -52,12 +49,6 @@ private:
|
||||
void paintDetailed( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
void paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, bool useAvatars = false ) const;
|
||||
|
||||
unsigned int m_removalProgress;
|
||||
|
||||
mutable QHash< qint64, QPixmap > m_cache;
|
||||
QPixmap m_nowPlayingIcon, m_defaultAvatar;
|
||||
mutable QPixmap m_arrowIcon;
|
||||
|
||||
QTextOption m_topOption;
|
||||
QTextOption m_bottomOption;
|
||||
|
||||
|
@ -584,6 +584,35 @@ Query::setLoved( bool loved )
|
||||
}
|
||||
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap
|
||||
Query::cover( const QSize& size, bool forceLoad ) const
|
||||
{
|
||||
if ( !forceLoad )
|
||||
return QPixmap();
|
||||
|
||||
if ( m_albumPtr.isNull() )
|
||||
{
|
||||
m_artistPtr = Artist::get( artist(), false );
|
||||
m_albumPtr = Album::get( m_artistPtr, album(), false );
|
||||
connect( m_artistPtr.data(), SIGNAL( updated() ), SIGNAL( updated() ), Qt::UniqueConnection );
|
||||
connect( m_albumPtr.data(), SIGNAL( updated() ), SIGNAL( updated() ), Qt::UniqueConnection );
|
||||
}
|
||||
|
||||
m_albumPtr->cover( size );
|
||||
if ( m_albumPtr->infoLoaded() )
|
||||
{
|
||||
if ( !m_albumPtr->cover( size ).isNull() )
|
||||
return m_albumPtr->cover( size );
|
||||
|
||||
return m_artistPtr->cover( size );
|
||||
}
|
||||
|
||||
return QPixmap();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
Query::levenshtein( const QString& source, const QString& target )
|
||||
{
|
||||
|
@ -103,6 +103,10 @@ public:
|
||||
unsigned int albumpos() const { return m_albumpos; }
|
||||
unsigned int discnumber() const { return m_discnumber; }
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap cover( const QSize& size, bool forceLoad = true ) const;
|
||||
#endif
|
||||
|
||||
void setResolveFinished( bool resolved ) { m_resolveFinished = resolved; }
|
||||
void setPlayedBy( const Tomahawk::source_ptr& source, unsigned int playtime );
|
||||
|
||||
@ -130,6 +134,7 @@ signals:
|
||||
|
||||
// emitted when social actions are loaded
|
||||
void socialActionsLoaded();
|
||||
void updated();
|
||||
|
||||
public slots:
|
||||
/// (indirectly) called by resolver plugins when results are found
|
||||
@ -144,7 +149,7 @@ public slots:
|
||||
// resolve if not solved()
|
||||
void onResolverAdded();
|
||||
void onResolverRemoved();
|
||||
|
||||
|
||||
private slots:
|
||||
void onResultStatusChanged();
|
||||
void refreshResults();
|
||||
@ -190,6 +195,9 @@ private:
|
||||
unsigned int m_discnumber;
|
||||
QString m_resultHint;
|
||||
|
||||
mutable Tomahawk::artist_ptr m_artistPtr;
|
||||
mutable Tomahawk::album_ptr m_albumPtr;
|
||||
|
||||
QPair< Tomahawk::source_ptr, unsigned int > m_playedBy;
|
||||
QList< QWeakPointer< Tomahawk::Resolver > > m_resolvers;
|
||||
|
||||
|
@ -128,17 +128,31 @@ Source::setAvatar( const QPixmap& avatar )
|
||||
|
||||
|
||||
QPixmap
|
||||
Source::avatar( AvatarStyle style ) const
|
||||
Source::avatar( AvatarStyle style, const QSize& size ) const
|
||||
{
|
||||
if ( style == FancyStyle && m_avatar && !m_fancyAvatar )
|
||||
m_fancyAvatar = new QPixmap( TomahawkUtils::createAvatarFrame( QPixmap( *m_avatar ) ) );
|
||||
|
||||
QPixmap pixmap;
|
||||
if ( style == Original && m_avatar )
|
||||
return QPixmap( *m_avatar );
|
||||
pixmap = *m_avatar;
|
||||
else if ( style == FancyStyle && m_fancyAvatar )
|
||||
return QPixmap( *m_fancyAvatar );
|
||||
else
|
||||
return QPixmap();
|
||||
pixmap = *m_fancyAvatar;
|
||||
|
||||
if ( !pixmap.isNull() && !size.isEmpty() )
|
||||
{
|
||||
if ( m_coverCache.contains( size.width() ) )
|
||||
{
|
||||
return m_coverCache.value( size.width() );
|
||||
}
|
||||
|
||||
QPixmap scaledCover;
|
||||
scaledCover = pixmap.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_coverCache.insert( size.width(), scaledCover );
|
||||
return scaledCover;
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
void setAvatar( const QPixmap& avatar );
|
||||
QPixmap avatar( AvatarStyle style = Original ) const;
|
||||
QPixmap avatar( AvatarStyle style = Original, const QSize& size = QSize() ) const;
|
||||
#endif
|
||||
|
||||
collection_ptr collection() const;
|
||||
@ -158,6 +158,7 @@ private:
|
||||
|
||||
QPixmap* m_avatar;
|
||||
mutable QPixmap* m_fancyAvatar;
|
||||
mutable QHash< int, QPixmap > m_coverCache;
|
||||
|
||||
Tomahawk::playlistinterface_ptr m_playlistInterface;
|
||||
};
|
||||
|
@ -46,12 +46,17 @@ namespace TomahawkUtils
|
||||
enum ImageType
|
||||
{
|
||||
DefaultAlbumCover,
|
||||
DefaultArtistImage
|
||||
DefaultArtistImage,
|
||||
DefaultTrackImage,
|
||||
DefaultSourceAvatar,
|
||||
NowPlayingSpeaker,
|
||||
InfoIcon
|
||||
};
|
||||
enum ImageMode
|
||||
{
|
||||
NoDefaultCover,
|
||||
Original,
|
||||
CoverInCase,
|
||||
AvatarInFrame,
|
||||
ScaledCover
|
||||
};
|
||||
|
||||
|
@ -341,6 +341,24 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size )
|
||||
pixmap = QPixmap( RESPATH "images/no-artist-image-placeholder.png" );
|
||||
break;
|
||||
|
||||
case DefaultTrackImage:
|
||||
pixmap = QPixmap( RESPATH "images/track-placeholder.png" );
|
||||
break;
|
||||
|
||||
case DefaultSourceAvatar:
|
||||
if ( mode == AvatarInFrame )
|
||||
pixmap = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) );
|
||||
else
|
||||
pixmap = QPixmap( RESPATH "images/user-avatar.png" );
|
||||
break;
|
||||
|
||||
case NowPlayingSpeaker:
|
||||
pixmap = QPixmap( RESPATH "images/now-playing-speaker.png" );
|
||||
break;
|
||||
|
||||
case InfoIcon:
|
||||
pixmap = QPixmap( RESPATH "images/info.png" );
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace TomahawkUtils
|
||||
DLLEXPORT int headerHeight();
|
||||
DLLEXPORT void setHeaderHeight( int height );
|
||||
|
||||
DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode, const QSize& size = QSize( 0, 0 ) );
|
||||
DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode = TomahawkUtils::Original, const QSize& size = QSize( 0, 0 ) );
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user