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:
commit
56cc0b1694
3 files changed
+67
-35
No files matched your search
@@ -15,7 +15,7 @@ class AppColors {
|
|||||||
static const Color background = Color(0xFF000000);
|
static const Color background = Color(0xFF000000);
|
||||||
|
|
||||||
/// Very deep grey for surfaces that need to be distinct but subtle (Apple Dark Grey)
|
/// 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
|
/// Slightly lighter grey for secondary surfaces or hover states
|
||||||
static const Color surfaceVariant = Color(0xFF3A3A3C);
|
static const Color surfaceVariant = Color(0xFF3A3A3C);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> with SingleTi
|
|||||||
// Glassmorphism Top Bar
|
// Glassmorphism Top Bar
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
extendBodyBehindAppBar: true, // Content behind app bar
|
extendBodyBehindAppBar: true, // Content behind app bar
|
||||||
backgroundColor: AppColors.background,
|
backgroundColor: Colors.transparent, // Transparent to show gradient
|
||||||
appBar: PreferredSize(
|
appBar: PreferredSize(
|
||||||
preferredSize: const Size.fromHeight(80),
|
preferredSize: const Size.fromHeight(80),
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -58,19 +58,43 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> with SingleTi
|
|||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
end: Alignment.bottomCenter,
|
end: Alignment.bottomCenter,
|
||||||
colors: [
|
colors: [
|
||||||
Colors.black.withOpacity(0.9), // Darker at top
|
Colors.black.withOpacity(0.6), // Subtler top shadow
|
||||||
Colors.transparent,
|
Colors.transparent,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Logo Area
|
// 1. Side Elements (Logo & Profile) - Pushed to edges
|
||||||
_buildLogo(),
|
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(),
|
// 2. Centered Navigation Tabs (Pills)
|
||||||
|
|
||||||
// Centered Navigation Tabs (Pills)
|
|
||||||
Container(
|
Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
decoration: BoxDecoration(
|
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(
|
body: Stack(
|
||||||
controller: _tabController,
|
|
||||||
physics: const NeverScrollableScrollPhysics(), // Disable swipe to avoid gesture conflicts
|
|
||||||
children: [
|
children: [
|
||||||
// Padding top to account for the transparent AppBar
|
// Background Gradient (Apple TV Depth Effect)
|
||||||
Padding(padding: const EdgeInsets.only(top: 80), child: LiveTVTab(playlist: widget.playlist)),
|
Container(
|
||||||
Padding(padding: const EdgeInsets.only(top: 80), child: MoviesTab(playlist: widget.playlist)),
|
decoration: const BoxDecoration(
|
||||||
Padding(padding: const EdgeInsets.only(top: 80), child: SeriesTab(playlist: widget.playlist)),
|
gradient: RadialGradient(
|
||||||
const Padding(padding: EdgeInsets.only(top: 80), child: SettingsTab()),
|
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,
|
vsync: this,
|
||||||
duration: const Duration(milliseconds: 1000)
|
duration: const Duration(milliseconds: 1000)
|
||||||
)..repeat(reverse: true);
|
)..repeat(reverse: true);
|
||||||
|
|
||||||
|
// Fetch EPG immediately when card is built
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_fetchEpg();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -107,7 +112,6 @@ class _ChannelCardState extends ConsumerState<ChannelCard>
|
|||||||
return MouseRegion(
|
return MouseRegion(
|
||||||
onEnter: (_) {
|
onEnter: (_) {
|
||||||
setState(() => _isHovered = true);
|
setState(() => _isHovered = true);
|
||||||
if (!_epgLoaded) _fetchEpg();
|
|
||||||
},
|
},
|
||||||
onExit: (_) => setState(() => _isHovered = false),
|
onExit: (_) => setState(() => _isHovered = false),
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
@@ -228,7 +232,7 @@ class _ChannelCardState extends ConsumerState<ChannelCard>
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if ((widget.currentProgram != null || _epgNow != null) && _isHovered) ...[
|
if ((widget.currentProgram != null || _epgNow != null)) ...[
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
_epgNow ?? widget.currentProgram ?? '',
|
_epgNow ?? widget.currentProgram ?? '',
|
||||||
|
|||||||
Reference in new issue
Block a user