This commit is contained in:
Broque Thomas 2025-07-24 12:56:46 -07:00
parent 2668d0613f
commit 4405e33aef

View file

@ -509,7 +509,7 @@ class PlaylistDetailsModal(QDialog):
def setup_ui(self): def setup_ui(self):
self.setWindowTitle(f"Playlist Details - {self.playlist.name}") self.setWindowTitle(f"Playlist Details - {self.playlist.name}")
self.setFixedSize(900, 700) self.setFixedSize(1200, 800)
self.setStyleSheet(""" self.setStyleSheet("""
QDialog { QDialog {
background: #191414; background: #191414;
@ -518,8 +518,8 @@ class PlaylistDetailsModal(QDialog):
""") """)
main_layout = QVBoxLayout(self) main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(30, 30, 30, 30) main_layout.setContentsMargins(32, 32, 32, 32)
main_layout.setSpacing(20) main_layout.setSpacing(24)
# Header section # Header section
header = self.create_header() header = self.create_header()
@ -537,59 +537,57 @@ class PlaylistDetailsModal(QDialog):
def create_header(self): def create_header(self):
header = QFrame() header = QFrame()
header.setFixedHeight(120)
header.setStyleSheet(""" header.setStyleSheet("""
QFrame { QFrame {
background: #282828; background: #282828;
border-radius: 12px; border-radius: 16px;
border: 1px solid #404040; border: 1px solid #404040;
} }
""") """)
layout = QVBoxLayout(header) layout = QVBoxLayout(header)
layout.setContentsMargins(25, 20, 25, 20) layout.setContentsMargins(32, 24, 32, 24)
layout.setSpacing(10) layout.setSpacing(12)
# Playlist name # Playlist name - larger, more prominent
name_label = QLabel(self.playlist.name) name_label = QLabel(self.playlist.name)
name_label.setFont(QFont("Arial", 20, QFont.Weight.Bold)) name_label.setFont(QFont("SF Pro Display", 24, QFont.Weight.Bold))
name_label.setStyleSheet("color: #ffffff; border: none; background: transparent;") name_label.setStyleSheet("color: #ffffff; border: none; background: transparent;")
# Playlist info # Playlist info in a more compact horizontal layout
info_layout = QHBoxLayout() info_layout = QHBoxLayout()
info_layout.setSpacing(20) info_layout.setSpacing(24)
# Track count # Track count with icon-like styling
track_count = QLabel(f"{self.playlist.total_tracks} tracks") track_count = QLabel(f"{self.playlist.total_tracks} tracks")
track_count.setFont(QFont("Arial", 12)) track_count.setFont(QFont("SF Pro Text", 14, QFont.Weight.Medium))
track_count.setStyleSheet("color: #b3b3b3; border: none; background: transparent;") track_count.setStyleSheet("color: #b3b3b3; border: none; background: transparent;")
# Owner # Owner with subtle separator
owner = QLabel(f"by {self.playlist.owner}") owner = QLabel(f"by {self.playlist.owner}")
owner.setFont(QFont("Arial", 12)) owner.setFont(QFont("SF Pro Text", 14))
owner.setStyleSheet("color: #b3b3b3; border: none; background: transparent;") owner.setStyleSheet("color: #b3b3b3; border: none; background: transparent;")
# Public/Private status # Status with accent color
visibility = "Public" if self.playlist.public else "Private" visibility = "Public" if self.playlist.public else "Private"
if self.playlist.collaborative: if self.playlist.collaborative:
visibility = "Collaborative" visibility = "Collaborative"
status = QLabel(visibility) status = QLabel(visibility)
status.setFont(QFont("Arial", 12)) status.setFont(QFont("SF Pro Text", 14, QFont.Weight.Medium))
status.setStyleSheet("color: #1db954; border: none; background: transparent;") status.setStyleSheet("""
color: #1db954;
border: none;
background: rgba(29, 185, 84, 0.1);
padding: 4px 12px;
border-radius: 12px;
""")
info_layout.addWidget(track_count) info_layout.addWidget(track_count)
info_layout.addWidget(owner) info_layout.addWidget(owner)
info_layout.addWidget(status) info_layout.addWidget(status)
info_layout.addStretch() info_layout.addStretch()
# Description (if available)
if self.playlist.description:
desc_label = QLabel(self.playlist.description)
desc_label.setFont(QFont("Arial", 11))
desc_label.setStyleSheet("color: #b3b3b3; border: none; background: transparent;")
desc_label.setWordWrap(True)
desc_label.setMaximumHeight(60)
layout.addWidget(desc_label)
layout.addWidget(name_label) layout.addWidget(name_label)
layout.addLayout(info_layout) layout.addLayout(info_layout)
@ -600,21 +598,16 @@ class PlaylistDetailsModal(QDialog):
container.setStyleSheet(""" container.setStyleSheet("""
QFrame { QFrame {
background: #282828; background: #282828;
border-radius: 12px; border-radius: 16px;
border: 1px solid #404040; border: 1px solid #404040;
} }
""") """)
layout = QVBoxLayout(container) layout = QVBoxLayout(container)
layout.setContentsMargins(25, 20, 25, 20) layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(15) layout.setSpacing(0)
# Section title # Track table with professional styling
title = QLabel("Tracks")
title.setFont(QFont("Arial", 16, QFont.Weight.Bold))
title.setStyleSheet("color: #ffffff; border: none; background: transparent;")
# Track table
self.track_table = QTableWidget() self.track_table = QTableWidget()
self.track_table.setColumnCount(4) self.track_table.setColumnCount(4)
self.track_table.setHorizontalHeaderLabels(["Track", "Artist", "Album", "Duration"]) self.track_table.setHorizontalHeaderLabels(["Track", "Artist", "Album", "Duration"])
@ -623,160 +616,198 @@ class PlaylistDetailsModal(QDialog):
track_count = len(self.playlist.tracks) if self.playlist.tracks else 1 track_count = len(self.playlist.tracks) if self.playlist.tracks else 1
self.track_table.setRowCount(track_count) self.track_table.setRowCount(track_count)
# Style the table # Professional table styling
self.track_table.setStyleSheet(""" self.track_table.setStyleSheet("""
QTableWidget { QTableWidget {
background: #181818; background: #282828;
border: 1px solid #404040; border: none;
border-radius: 8px; border-radius: 16px;
gridline-color: #404040; gridline-color: transparent;
color: #ffffff; color: #ffffff;
font-size: 11px; font-size: 13px;
selection-background-color: rgba(29, 185, 84, 0.2);
} }
QTableWidget::item { QTableWidget::item {
padding: 8px; padding: 16px 24px;
border-bottom: 1px solid #333333; border-bottom: 1px solid rgba(255, 255, 255, 0.05);
background: transparent;
}
QTableWidget::item:hover {
background: rgba(255, 255, 255, 0.02);
} }
QTableWidget::item:selected { QTableWidget::item:selected {
background: #1db954; background: rgba(29, 185, 84, 0.15);
color: #000000; color: #ffffff;
}
QHeaderView {
background: transparent;
border: none;
} }
QHeaderView::section { QHeaderView::section {
background: #404040; background: transparent;
color: #ffffff; color: #b3b3b3;
padding: 10px; padding: 16px 24px;
border: none; border: none;
font-weight: bold; border-bottom: 2px solid rgba(255, 255, 255, 0.1);
font-size: 11px; font-weight: 600;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
QHeaderView::section:hover {
background: rgba(255, 255, 255, 0.02);
} }
""") """)
# Populate table # Populate table with proper styling
if self.playlist.tracks: if self.playlist.tracks:
for row, track in enumerate(self.playlist.tracks): for row, track in enumerate(self.playlist.tracks):
# Track name # Track name with proper styling
track_item = QTableWidgetItem(track.name) track_item = QTableWidgetItem(track.name)
track_item.setFlags(track_item.flags() & ~Qt.ItemFlag.ItemIsEditable) track_item.setFlags(track_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
track_item.setFont(QFont("SF Pro Text", 13, QFont.Weight.Medium))
self.track_table.setItem(row, 0, track_item) self.track_table.setItem(row, 0, track_item)
# Artist(s) # Artist(s) with subtle styling
artists = ", ".join(track.artists) artists = ", ".join(track.artists)
artist_item = QTableWidgetItem(artists) artist_item = QTableWidgetItem(artists)
artist_item.setFlags(artist_item.flags() & ~Qt.ItemFlag.ItemIsEditable) artist_item.setFlags(artist_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
artist_item.setFont(QFont("SF Pro Text", 13))
self.track_table.setItem(row, 1, artist_item) self.track_table.setItem(row, 1, artist_item)
# Album # Album with subtle styling
album_item = QTableWidgetItem(track.album) album_item = QTableWidgetItem(track.album)
album_item.setFlags(album_item.flags() & ~Qt.ItemFlag.ItemIsEditable) album_item.setFlags(album_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
album_item.setFont(QFont("SF Pro Text", 13))
self.track_table.setItem(row, 2, album_item) self.track_table.setItem(row, 2, album_item)
# Duration # Duration with monospace font
duration = self.format_duration(track.duration_ms) duration = self.format_duration(track.duration_ms)
duration_item = QTableWidgetItem(duration) duration_item = QTableWidgetItem(duration)
duration_item.setFlags(duration_item.flags() & ~Qt.ItemFlag.ItemIsEditable) duration_item.setFlags(duration_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
duration_item.setFont(QFont("SF Mono", 12))
self.track_table.setItem(row, 3, duration_item) self.track_table.setItem(row, 3, duration_item)
else: else:
# Show placeholder while tracks are being loaded # Show placeholder while tracks are being loaded
placeholder_item = QTableWidgetItem("Tracks will load momentarily...") placeholder_item = QTableWidgetItem("Loading tracks...")
placeholder_item.setFlags(placeholder_item.flags() & ~Qt.ItemFlag.ItemIsEditable) placeholder_item.setFlags(placeholder_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
self.track_table.setItem(0, 0, placeholder_item) self.track_table.setItem(0, 0, placeholder_item)
self.track_table.setSpan(0, 0, 1, 4) self.track_table.setSpan(0, 0, 1, 4)
# Set optimal column widths with proportional sizing # Professional column configuration
header = self.track_table.horizontalHeader() header = self.track_table.horizontalHeader()
header.setVisible(True)
header.show()
header.setStretchLastSection(False) header.setStretchLastSection(False)
header.setHighlightSections(False)
header.setDefaultAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
# Calculate available width (modal is 900px, account for margins/scrollbar) # Calculate available width (modal is 1200px, account for margins)
available_width = 850 available_width = 1136 # 1200 - 64px margins
# Set proportional widths: Track(40%), Artist(25%), Album(25%), Duration(10%) # Professional proportional widths
track_width = int(available_width * 0.40) # ~340px track_width = int(available_width * 0.35) # ~398px
artist_width = int(available_width * 0.25) # ~212px artist_width = int(available_width * 0.28) # ~318px
album_width = int(available_width * 0.25) # ~212px album_width = int(available_width * 0.28) # ~318px
duration_width = 80 # Fixed 80px duration_width = 100 # Fixed 100px
# Apply column widths with interactive resize capability # Apply column widths with proper resize modes
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Interactive) # Track name header.setSectionResizeMode(0, QHeaderView.ResizeMode.Interactive)
header.setSectionResizeMode(1, QHeaderView.ResizeMode.Interactive) # Artist header.setSectionResizeMode(1, QHeaderView.ResizeMode.Interactive)
header.setSectionResizeMode(2, QHeaderView.ResizeMode.Interactive) # Album header.setSectionResizeMode(2, QHeaderView.ResizeMode.Interactive)
header.setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed) # Duration header.setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed)
self.track_table.setColumnWidth(0, track_width) self.track_table.setColumnWidth(0, track_width)
self.track_table.setColumnWidth(1, artist_width) self.track_table.setColumnWidth(1, artist_width)
self.track_table.setColumnWidth(2, album_width) self.track_table.setColumnWidth(2, album_width)
self.track_table.setColumnWidth(3, duration_width) self.track_table.setColumnWidth(3, duration_width)
# Set minimum widths to prevent columns from becoming too narrow # Set minimum widths for professional look
header.setMinimumSectionSize(100) # Minimum 100px for any column header.setMinimumSectionSize(120)
# Hide row numbers # Hide row numbers and configure table behavior
self.track_table.verticalHeader().setVisible(False) self.track_table.verticalHeader().setVisible(False)
self.track_table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.track_table.setAlternatingRowColors(False)
layout.addWidget(title)
layout.addWidget(self.track_table) layout.addWidget(self.track_table)
return container return container
def create_buttons(self): def create_buttons(self):
button_layout = QHBoxLayout() button_layout = QHBoxLayout()
button_layout.setSpacing(15) button_layout.setSpacing(16)
button_layout.setContentsMargins(0, 0, 0, 0)
# Close button # Close button with subtle styling
close_btn = QPushButton("Close") close_btn = QPushButton("Close")
close_btn.setFixedSize(100, 40) close_btn.setFixedSize(100, 44)
close_btn.clicked.connect(self.close) close_btn.clicked.connect(self.close)
close_btn.setStyleSheet(""" close_btn.setStyleSheet("""
QPushButton { QPushButton {
background: #404040; background: rgba(255, 255, 255, 0.05);
border: none; border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px; border-radius: 22px;
color: #ffffff; color: #ffffff;
font-size: 12px; font-size: 13px;
font-weight: bold; font-weight: 600;
font-family: 'SF Pro Text';
} }
QPushButton:hover { QPushButton:hover {
background: #505050; background: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.15);
}
QPushButton:pressed {
background: rgba(255, 255, 255, 0.02);
} }
""") """)
# Sync button # Download missing tracks button with outline style
sync_btn = QPushButton("Sync This Playlist")
sync_btn.setFixedSize(150, 40)
sync_btn.setStyleSheet("""
QPushButton {
background: #1db954;
border: none;
border-radius: 20px;
color: #000000;
font-size: 12px;
font-weight: bold;
}
QPushButton:hover {
background: #1ed760;
}
""")
# Download missing tracks button
download_btn = QPushButton("Download Missing Tracks") download_btn = QPushButton("Download Missing Tracks")
download_btn.setFixedSize(180, 40) download_btn.setFixedSize(200, 44)
download_btn.setStyleSheet(""" download_btn.setStyleSheet("""
QPushButton { QPushButton {
background: transparent; background: transparent;
border: 1px solid #1db954; border: 1px solid #1db954;
border-radius: 20px; border-radius: 22px;
color: #1db954; color: #1db954;
font-size: 12px; font-size: 13px;
font-weight: bold; font-weight: 600;
font-family: 'SF Pro Text';
} }
QPushButton:hover { QPushButton:hover {
background: rgba(29, 185, 84, 0.1); background: rgba(29, 185, 84, 0.08);
border-color: #1ed760;
color: #1ed760;
}
QPushButton:pressed {
background: rgba(29, 185, 84, 0.15);
} }
""") """)
# Connect download missing tracks button # Sync button with primary styling
download_btn.clicked.connect(self.on_download_missing_tracks_clicked) sync_btn = QPushButton("Sync This Playlist")
sync_btn.setFixedSize(160, 44)
sync_btn.setStyleSheet("""
QPushButton {
background: #1db954;
border: none;
border-radius: 22px;
color: #ffffff;
font-size: 13px;
font-weight: 600;
font-family: 'SF Pro Text';
}
QPushButton:hover {
background: #1ed760;
}
QPushButton:pressed {
background: #169c46;
}
""")
# Connect sync button # Connect button signals
download_btn.clicked.connect(self.on_download_missing_tracks_clicked)
sync_btn.clicked.connect(self.on_sync_playlist_clicked) sync_btn.clicked.connect(self.on_sync_playlist_clicked)
button_layout.addStretch() button_layout.addStretch()