mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-11 17:30:00 +02:00
Merge pull request #61 from R0m1k3/antigravity
feat: implement ChannelCard widget with EPG display, interactive hove…
This commit is contained in:
3 files changed
+67
-35
No files matched your search
@@ -15,7 +15,7 @@ class AppColors {
|
||||
static const Color background = Color(0xFF000000);
|
||||
|
||||
/// Very deep grey for surfaces that need to be distinct but subtle (Apple Dark Grey)
|
||||
static const Color surface = Color(0xFF2C2C2E);
|
||||
static const Color surface = Color(0xFF1C1C1E);
|
||||
|
||||
/// Slightly lighter grey for secondary surfaces or hover states
|
||||
static const Color surfaceVariant = Color(0xFF3A3A3C);
|
||||
|
||||
@@ -48,7 +48,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> with SingleTi
|
||||
// Glassmorphism Top Bar
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true, // Content behind app bar
|
||||
backgroundColor: AppColors.background,
|
||||
backgroundColor: Colors.transparent, // Transparent to show gradient
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(80),
|
||||
child: Container(
|
||||
@@ -58,19 +58,43 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> with SingleTi
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.black.withOpacity(0.9), // Darker at top
|
||||
Colors.black.withOpacity(0.6), // Subtler top shadow
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// Logo Area
|
||||
_buildLogo(),
|
||||
// 1. Side Elements (Logo & Profile) - Pushed to edges
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Logo Area
|
||||
_buildLogo(),
|
||||
|
||||
// Search / Profile (Right Side)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.search, color: Colors.white),
|
||||
onPressed: () {
|
||||
// Global search trigger
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor: Colors.white24,
|
||||
child: Icon(Icons.person, size: 18, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const Spacer(),
|
||||
|
||||
// Centered Navigation Tabs (Pills)
|
||||
// 2. Centered Navigation Tabs (Pills)
|
||||
Container(
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
@@ -108,35 +132,39 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> with SingleTi
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
const Spacer(),
|
||||
|
||||
// Search / Profile (Right Side)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.search, color: Colors.white),
|
||||
onPressed: () {
|
||||
// Global search trigger
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor: Colors.white24,
|
||||
child: Icon(Icons.person, size: 18, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
controller: _tabController,
|
||||
physics: const NeverScrollableScrollPhysics(), // Disable swipe to avoid gesture conflicts
|
||||
body: Stack(
|
||||
children: [
|
||||
// Padding top to account for the transparent AppBar
|
||||
Padding(padding: const EdgeInsets.only(top: 80), child: LiveTVTab(playlist: widget.playlist)),
|
||||
Padding(padding: const EdgeInsets.only(top: 80), child: MoviesTab(playlist: widget.playlist)),
|
||||
Padding(padding: const EdgeInsets.only(top: 80), child: SeriesTab(playlist: widget.playlist)),
|
||||
const Padding(padding: EdgeInsets.only(top: 80), child: SettingsTab()),
|
||||
// Background Gradient (Apple TV Depth Effect)
|
||||
Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: RadialGradient(
|
||||
center: Alignment(0, -0.2), // Slightly above center
|
||||
radius: 1.5,
|
||||
colors: [
|
||||
Color(0xFF2C2C2E), // Dark Grey center (Light Source)
|
||||
Color(0xFF000000), // Pure Black edges
|
||||
],
|
||||
stops: [0.0, 1.0],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Content
|
||||
TabBarView(
|
||||
controller: _tabController,
|
||||
physics: const NeverScrollableScrollPhysics(), // Disable swipe to avoid gesture conflicts
|
||||
children: [
|
||||
// Padding top to account for the transparent AppBar
|
||||
Padding(padding: const EdgeInsets.only(top: 80), child: LiveTVTab(playlist: widget.playlist)),
|
||||
Padding(padding: const EdgeInsets.only(top: 80), child: MoviesTab(playlist: widget.playlist)),
|
||||
Padding(padding: const EdgeInsets.only(top: 80), child: SeriesTab(playlist: widget.playlist)),
|
||||
const Padding(padding: EdgeInsets.only(top: 80), child: SettingsTab()),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -52,6 +52,11 @@ class _ChannelCardState extends ConsumerState<ChannelCard>
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 1000)
|
||||
)..repeat(reverse: true);
|
||||
|
||||
// Fetch EPG immediately when card is built
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_fetchEpg();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -107,7 +112,6 @@ class _ChannelCardState extends ConsumerState<ChannelCard>
|
||||
return MouseRegion(
|
||||
onEnter: (_) {
|
||||
setState(() => _isHovered = true);
|
||||
if (!_epgLoaded) _fetchEpg();
|
||||
},
|
||||
onExit: (_) => setState(() => _isHovered = false),
|
||||
cursor: SystemMouseCursors.click,
|
||||
@@ -228,7 +232,7 @@ class _ChannelCardState extends ConsumerState<ChannelCard>
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
if ((widget.currentProgram != null || _epgNow != null) && _isHovered) ...[
|
||||
if ((widget.currentProgram != null || _epgNow != null)) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
_epgNow ?? widget.currentProgram ?? '',
|
||||
|
||||
Reference in new issue
Block a user