uplink 1.0.0 copy "uplink: ^1.0.0" to clipboard
uplink: ^1.0.0 copied to clipboard

An unstoppable, high-performance background media upload engine with swipe-kill resilience, hardware locks, and auto-retry sync.

example/lib/main.dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:uplink/uplink.dart';
import 'package:file_picker/file_picker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'UpLink Background Uploader',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple, brightness: Brightness.dark),
        useMaterial3: true,
      ),
      home: const UploadDashboard(),
    );
  }
}

class UploadDashboard extends StatefulWidget {
  const UploadDashboard({super.key});

  @override
  State<UploadDashboard> createState() => _UploadDashboardState();
}

class _UploadDashboardState extends State<UploadDashboard> {
  final String _testUrl = "https://httpbin.org/post"; // Highly reliable testing URL
  
  List<UploadTask> _savedTasks = [];
  String? _currentActiveId;
  int _currentProgress = 0;
  String _currentStatus = "idle";

  @override
  void initState() {
    super.initState();
    UpLink.requestNotificationPermission();
    _loadTasks();
    _listenToProgress();
  }

  void _loadTasks() async {
    final tasks = await UpLink.getAllTasks();
    setState(() {
      _savedTasks = tasks;
    });
  }

  void _listenToProgress() {
    UpLink.onProgress.listen((event) {
      print("Stream received progress: ${event.id} -> ${event.progress}% [${event.status}]");
      setState(() {
        _currentActiveId = event.id;
        _currentProgress = event.progress;
        _currentStatus = event.status;
      });
      // Refresh saved lists whenever tasks finish
      if (event.status == 'completed' || event.status == 'failed') {
        _loadTasks();
      }
    });
  }

  Future<void> _pickAndUploadRealMedia() async {
    try {
      // Pick multiple images or videos from phone gallery
      final result = await FilePicker.platform.pickFiles(
        type: FileType.media,
        allowMultiple: true,
      );

      if (result != null && result.files.isNotEmpty) {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text("Enqueuing ${result.files.length} background tasks...")),
        );

        // Loop through each selected file and enqueue separately
        for (var file in result.files) {
          if (file.path != null) {
            final filePath = file.path!;
            final fileName = file.name;

            // Queue each file independently
            final String taskId = await UpLink.enqueue(
              url: _testUrl,
              filePath: filePath,
              headers: {
                "Authorization": "Bearer my-auth-token",
                "Content-Name": fileName,
              },
            );
            print("Enqueued multiple-task success ID: $taskId for $fileName");
          }
        }
        _loadTasks();
      } else {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text("No media files were selected.")),
        );
      }
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("Picker Error: $e")),
      );
    }
  }

  Future<void> _startTestUpload() async {
    try {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text("Preparing 10MB Test File...")),
      );

      // Dynamically generate a reliable 10MB test file locally
      final tempDir = Directory.systemTemp;
      final file = File('${tempDir.path}/uplink_test_file.bin');
      
      if (!await file.exists()) {
        final sink = file.openWrite();
        final List<int> chunk = List<int>.generate(1024 * 100, (_) => 0); // 100KB
        for (int i = 0; i < 100; i++) {
          sink.add(chunk);
        }
        await sink.flush();
        await sink.close();
      }

      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text("Enqueuing Dummy Task...")),
      );

      // Triggers the complete system
      final String taskId = await UpLink.enqueue(
        url: _testUrl,
        filePath: file.path,
        headers: {
          "Authorization": "Bearer dummy-token-123",
          "Custom-Header": "UpLink-Agent"
        },
      );

      print("Enqueued Task ID: $taskId at ${file.path}");
      _loadTasks();
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("Error: $e")),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('UpLink Dashboard 🚀'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _loadTasks,
          )
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Active Task Card
            Card(
              color: Colors.deepPurple.shade900.withAlpha(77),
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      "Live Stream (EventChannel)",
                      style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
                    ),
                    const SizedBox(height: 10),
                    Text("Task: ${_currentActiveId ?? 'None Active'}"),
                    const SizedBox(height: 5),
                    Row(
                      children: [
                        Expanded(
                          child: LinearProgressIndicator(
                            value: _currentProgress / 100.0,
                            backgroundColor: Colors.grey.shade800,
                          ),
                        ),
                        const SizedBox(width: 10),
                        Text("$_currentProgress%"),
                      ],
                    ),
                    const SizedBox(height: 5),
                    Text(
                      "Status: ${_currentStatus.toUpperCase()}",
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        color: _currentStatus == "running" ? Colors.orangeAccent : Colors.greenAccent,
                      ),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 20),
            
            // Real Media Picker Button
            ElevatedButton.icon(
              style: ElevatedButton.styleFrom(
                minimumSize: const Size.fromHeight(55),
                backgroundColor: Colors.deepPurple,
                foregroundColor: Colors.white,
              ),
              icon: const Icon(Icons.perm_media),
              label: const Text("📷 Pick & Upload Real Media", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              onPressed: _pickAndUploadRealMedia,
            ),
            const SizedBox(height: 12),
            
            // Dummy Task Button
            OutlinedButton.icon(
              style: OutlinedButton.styleFrom(
                minimumSize: const Size.fromHeight(50),
              ),
              icon: const Icon(Icons.cloud_upload),
              label: const Text("Enqueue 10MB Dummy File"),
              onPressed: _startTestUpload,
            ),
            
            const Divider(height: 40),
            const Text(
              "Database Log (SQLite History)",
              style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
            ),
            const SizedBox(height: 10),
            Expanded(
              child: _savedTasks.isEmpty
                  ? const Center(child: Text("No stored tasks found in SQLite"))
                  : ListView.builder(
                      itemCount: _savedTasks.length,
                      itemBuilder: (context, index) {
                        final task = _savedTasks[index];
                        final displayPath = task.filePath.split('/').last;
                        return Card(
                          child: ListTile(
                            leading: Icon(
                              task.status == UploadStatus.completed
                                  ? Icons.check_circle
                                  : Icons.pending,
                              color: task.status == UploadStatus.completed
                                  ? Colors.green
                                  : Colors.orange,
                            ),
                            title: Text(
                              "File: $displayPath",
                              style: const TextStyle(fontWeight: FontWeight.bold),
                            ),
                            subtitle: Text("Status: ${task.status.name}\nProgress: ${task.progress}%"),
                            trailing: IconButton(
                              icon: const Icon(Icons.delete, color: Colors.redAccent),
                              onPressed: () async {
                                await UpLink.deleteTask(task.id);
                                _loadTasks();
                              },
                            ),
                          ),
                        );
                      },
                    ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
0
points
12
downloads

Publisher

unverified uploader

Weekly Downloads

An unstoppable, high-performance background media upload engine with swipe-kill resilience, hardware locks, and auto-retry sync.

Homepage

License

unknown (license)

Dependencies

flutter, path, plugin_platform_interface, sqflite, uuid

More

Packages that depend on uplink

Packages that implement uplink