mirror of
https://github.com/R0m1k3/xtremobile.git
synced 2026-10-21 22:28:16 +02:00
feat: Implement MobileMoviesTab for displaying IPTV movies with category browsing and search functionality.
This commit is contained in:
1 parent
0010fe12ba
commit
f85f43e42f
17 files changed
+268
-136
No files matched your search
@@ -9,6 +9,7 @@
|
||||
/// - Result: Same hostname resolved twice, wasting network calls
|
||||
///
|
||||
/// Solution: Single unified service with shared cache
|
||||
library;
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
@@ -166,6 +167,5 @@ class _DnsCacheEntry {
|
||||
|
||||
_DnsCacheEntry(this.ip) : timestamp = DateTime.now();
|
||||
|
||||
bool get isExpired =>
|
||||
DateTime.now().difference(timestamp).inSeconds > 3600;
|
||||
bool get isExpired => DateTime.now().difference(timestamp).inSeconds > 3600;
|
||||
}
|
||||
@@ -35,10 +35,14 @@ class StreamResolverPattern {
|
||||
}
|
||||
|
||||
// Parallel resolution attempts
|
||||
final results = await Future.wait([
|
||||
_validateUrl(streamUrl).timeout(timeout, onTimeout: () => false),
|
||||
_performDnsResolution(streamUrl).timeout(timeout, onTimeout: () => false),
|
||||
], eagerError: false).catchError((_) => [false, false]);
|
||||
final results = await Future.wait(
|
||||
[
|
||||
_validateUrl(streamUrl).timeout(timeout, onTimeout: () => false),
|
||||
_performDnsResolution(streamUrl)
|
||||
.timeout(timeout, onTimeout: () => false),
|
||||
],
|
||||
eagerError: false,
|
||||
).catchError((_) => [false, false]);
|
||||
|
||||
final isValid = results[0];
|
||||
final dnsResolved = results[1];
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
|
||||
/// Video player selection and wrapper pattern
|
||||
/// Abstracts between MediaKit and other video players
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user