feat: Implement MobileMoviesTab for displaying IPTV movies with category browsing and search functionality.

This commit is contained in:
Michael committed 2026-03-27 12:10:23 +01:00
1 parent 0010fe12ba
commit f85f43e42f
17 files changed
+268 -136

No files matched your search

+1
View File
@@ -2,6 +2,7 @@
///
/// Detects device RAM and adjusts player buffer size accordingly
/// to prevent OOM crashes on low-end devices
library;
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
+26 -13
View File
@@ -13,7 +13,7 @@ class HiveEncryptionBenchmark {
String valueSize = 'medium', // small, medium, large
}) async {
if (kDebugMode) {
print('\n' + ('=' * 60));
print('\n${'=' * 60}');
print('🔐 HIVE ENCRYPTION BENCHMARK');
print('=' * 60);
print('Write Operations: $writeCount');
@@ -42,7 +42,10 @@ class HiveEncryptionBenchmark {
}
static Future<void> _benchmarkUnencrypted(
int writes, int reads, String testValue) async {
int writes,
int reads,
String testValue,
) async {
const boxName = 'benchmark_unencrypted';
try {
// Clean up if exists
@@ -62,7 +65,7 @@ class HiveEncryptionBenchmark {
// Read benchmark
final readStop = Stopwatch()..start();
for (int i = 0; i < reads; i++) {
await box.get('key_${i % writes}');
box.get('key_${i % writes}');
}
readStop.stop();
@@ -93,7 +96,10 @@ class HiveEncryptionBenchmark {
}
static Future<void> _benchmarkEncrypted(
int writes, int reads, String testValue) async {
int writes,
int reads,
String testValue,
) async {
const boxName = 'benchmark_encrypted';
try {
// Clean up if exists
@@ -118,7 +124,7 @@ class HiveEncryptionBenchmark {
// Read benchmark
final readStop = Stopwatch()..start();
for (int i = 0; i < reads; i++) {
await box.get('key_${i % writes}');
box.get('key_${i % writes}');
}
readStop.stop();
@@ -157,21 +163,25 @@ class HiveEncryptionBenchmark {
final readOverhead = ((enc.readTimeMs / unenc.readTimeMs - 1) * 100);
if (kDebugMode) {
print('\n' + ('=' * 60));
print('\n${'=' * 60}');
print('📊 PERFORMANCE COMPARISON');
print('=' * 60);
print('\nWrite Performance:');
print(
' Unencrypted: ${unenc.writeTimeMs}ms (${(unenc.writeTimeMs / unenc.operationCount).toStringAsFixed(2)}µs/op)');
' Unencrypted: ${unenc.writeTimeMs}ms (${(unenc.writeTimeMs / unenc.operationCount).toStringAsFixed(2)}µs/op)',
);
print(
' Encrypted: ${enc.writeTimeMs}ms (${(enc.writeTimeMs / enc.operationCount).toStringAsFixed(2)}µs/op)');
' Encrypted: ${enc.writeTimeMs}ms (${(enc.writeTimeMs / enc.operationCount).toStringAsFixed(2)}µs/op)',
);
print(' Overhead: ${writeOverhead.toStringAsFixed(1)}%');
print('\nRead Performance:');
print(
' Unencrypted: ${unenc.readTimeMs}ms (${(unenc.readTimeMs / unenc.operationCount).toStringAsFixed(2)}µs/op)');
' Unencrypted: ${unenc.readTimeMs}ms (${(unenc.readTimeMs / unenc.operationCount).toStringAsFixed(2)}µs/op)',
);
print(
' Encrypted: ${enc.readTimeMs}ms (${(enc.readTimeMs / enc.operationCount).toStringAsFixed(2)}µs/op)');
' Encrypted: ${enc.readTimeMs}ms (${(enc.readTimeMs / enc.operationCount).toStringAsFixed(2)}µs/op)',
);
print(' Overhead: ${readOverhead.toStringAsFixed(1)}%');
// Status
@@ -180,8 +190,10 @@ class HiveEncryptionBenchmark {
final readStatus = readOverhead > acceptableThreshold ? '⚠️' : '✅';
print('\nStatus:');
print(' $writeStatus Write overhead: ${writeOverhead.toStringAsFixed(1)}% (target: <$acceptableThreshold%)');
print(' $readStatus Read overhead: ${readOverhead.toStringAsFixed(1)}% (target: <$acceptableThreshold%)');
print(
' $writeStatus Write overhead: ${writeOverhead.toStringAsFixed(1)}% (target: <$acceptableThreshold%)');
print(
' $readStatus Read overhead: ${readOverhead.toStringAsFixed(1)}% (target: <$acceptableThreshold%)');
print('=' * 60 + '\n');
}
}
@@ -229,7 +241,8 @@ class EncryptionBenchmarkResult {
void print() {
print(' Name: $name');
print(' Write: ${writeTimeMs}ms (${writePerOpUs.toStringAsFixed(2)}µs/op)');
print(
' Write: ${writeTimeMs}ms (${writePerOpUs.toStringAsFixed(2)}µs/op)');
print(' Read: ${readTimeMs}ms (${readPerOpUs.toStringAsFixed(2)}µs/op)');
print(' Delete: ${deleteTimeMs}ms');
}
+2 -1
View File
@@ -5,6 +5,7 @@
/// but displays them at 40-100px sizes, wasting memory and disk space.
///
/// Solution: Specify memCacheWidth/Height for display size, limiting disk cache.
library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
@@ -29,7 +30,7 @@ class ImageCacheConfigs {
static const ImageCacheConfig channelIcon = ImageCacheConfig(
displayWidth: 40,
displayHeight: 40,
cacheWidth: 50, // Slight buffer for upscaling
cacheWidth: 50, // Slight buffer for upscaling
cacheHeight: 50,
);
+11 -8
View File
@@ -35,7 +35,8 @@ class MemoryProfiler {
count++;
});
if (kDebugMode) {
print('⏰ PERIODIC MEMORY MONITORING STARTED (${interval.inSeconds}s interval)');
print(
'⏰ PERIODIC MEMORY MONITORING STARTED (${interval.inSeconds}s interval)');
}
}
@@ -50,9 +51,10 @@ class MemoryProfiler {
/// Analyze memory growth between snapshots
static MemoryAnalysis analyzeGrowth(String startLabel, String endLabel) {
final start =
_snapshots.firstWhere((s) => s.label == startLabel, orElse: () => _snapshots.first);
final end = _snapshots.firstWhere((s) => s.label == endLabel, orElse: () => _snapshots.last);
final start = _snapshots.firstWhere((s) => s.label == startLabel,
orElse: () => _snapshots.first);
final end = _snapshots.firstWhere((s) => s.label == endLabel,
orElse: () => _snapshots.last);
return MemoryAnalysis(
startLabel: startLabel,
@@ -65,7 +67,7 @@ class MemoryProfiler {
/// Generate report
static void printReport() {
if (kDebugMode) {
print('\n' + ('=' * 60));
print('\n${'=' * 60}');
print('📊 MEMORY PROFILING REPORT');
print('=' * 60);
for (int i = 0; i < _snapshots.length; i++) {
@@ -75,19 +77,20 @@ class MemoryProfiler {
// Show growth analysis
if (_snapshots.length >= 2) {
print('\n' + ('-' * 60));
print('\n${'-' * 60}');
print('📈 GROWTH ANALYSIS');
print('-' * 60);
for (int i = 0; i < _snapshots.length - 1; i++) {
final snapshot = _snapshots[i];
final nextSnapshot = _snapshots[i + 1];
final growth = nextSnapshot.description.compareTo(snapshot.description);
final growth =
nextSnapshot.description.compareTo(snapshot.description);
print(' ${snapshot.label} → ${nextSnapshot.label}: $growth');
}
}
print('\n' + ('=' * 60) + '\n');
print('\n${'=' * 60}\n');
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ class StartupProfiler {
/// Report all metrics
static Future<void> reportAll() async {
if (kDebugMode) {
print('\n' + ('=' * 50));
print('\n${'=' * 50}');
print('⏱️ STARTUP METRICS');
print('=' * 50);
_timings.forEach((key, watch) {
+4 -6
View File
@@ -32,8 +32,7 @@ class VideoProfiler {
static void markFirstFrame(String streamName) {
final m = metrics[streamName];
if (m != null) {
m.firstFrameTime =
DateTime.now().difference(m.loadStart).inMilliseconds;
m.firstFrameTime = DateTime.now().difference(m.loadStart).inMilliseconds;
if (kDebugMode) {
print('🎬 FIRST FRAME: ${m.firstFrameTime}ms');
}
@@ -78,10 +77,9 @@ class VideoProfiler {
final m = metrics[streamName];
if (m != null) {
m.endTime = DateTime.now();
m.totalDurationMs =
m.endTime!.difference(m.startTime).inMilliseconds;
m.totalDurationMs = m.endTime!.difference(m.startTime).inMilliseconds;
if (kDebugMode) {
print('\n' + ('=' * 50));
print('\n${'=' * 50}');
print('📊 VIDEO METRICS: $streamName');
print('=' * 50);
m.printMetrics();
@@ -93,7 +91,7 @@ class VideoProfiler {
/// Get summary of all metrics
static void printSummary() {
if (kDebugMode) {
print('\n' + ('=' * 50));
print('\n${'=' * 50}');
print('📈 VIDEO PROFILING SUMMARY');
print('=' * 50);
metrics.forEach((key, m) {