Skip to content

Latest commit

 

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Proxync

Proxync is a Flutter file-sharing app built for local network transfers. It uses Riverpod for state management, Bonsoir for device discovery, and a socket-based transfer flow for sending and receiving files between nearby devices.

Project Overview

The app is organized around three main user flows:

  • Send files to nearby devices on the same network.
  • Receive incoming transfer requests and save files locally.
  • Review sent and received transfer history.

The current UI is split into three areas:

  • Send
  • Receive
  • History

Requirements

  • Flutter SDK 3.10.8 or newer
  • Dart 3.10.x
  • Android Studio, VS Code, or another Flutter-compatible editor
  • A physical Android or iOS device on the same Wi-Fi network for local transfer testing

How to Run

1. Install dependencies

Run the following command from the project root:

flutter pub get

2. Check your connected device

Verify that Flutter can see your device or emulator:

flutter devices

3. Start the app

Run the application on the selected device:

flutter run

If you want to target a specific device, use the device id from flutter devices:

flutter run -d <device_id>

4. Android permissions

For discovery and file access to work correctly on Android, grant the requested permissions when the app prompts you. Depending on your device and Android version, this may include:

  • Location
  • Nearby Wi-Fi devices
  • Storage or file access permissions
  • Manage external storage for saving files to the public Downloads folder

5. Same-network requirement

Both devices must be on the same local Wi-Fi network for discovery and transfer to work.

How the App Works

Startup flow

The app starts from lib/main.dart, where ProviderScope wraps the app so Riverpod providers can manage shared state.

Route generation is handled by AppRoutes.generateRoute, and the home route loads AppInitializer, which starts the background services before showing the main navigation shell.

Send flow

The Send tab lets the user pick files through the file picker service and shows nearby devices discovered on the network.

When a device is selected, FileSenderService.sendFile():

  • connects to the target IP and port,
  • sends metadata first,
  • waits for an accept or decline response,
  • streams the file in chunks if accepted,
  • reports progress back to the UI.

Receive flow

The Receive tab keeps the device discoverable and shows pending incoming requests.

When a transfer request arrives, TransferService:

  • accepts the socket connection,
  • decodes the metadata message,
  • adds the request to the incoming transfer state,
  • waits for the user to accept or decline,
  • writes the file to storage when accepted,
  • updates transfer history after completion or failure.

History flow

The History tab shows a grouped timeline of sent and received transfers. History entries are stored with SharedPreferences, so they persist across app restarts.

Architecture

Proxync follows a feature-first architecture with a shared core layer.

Core layer

The lib/core directory contains reusable app infrastructure:

  • route/ for route generation
  • services/ for network, transfer, file, and device utilities
  • providers/ for shared Riverpod providers
  • models/ for data structures used across features
  • widgets/ for app-wide UI building blocks

Feature layer

Each feature lives under lib/features:

  • send/ handles file selection and nearby device sending
  • receive/ handles incoming transfer requests and acceptance
  • history/ stores and renders transfer history

State management

Riverpod is used to keep state isolated and reactive. Providers manage:

  • nearby device discovery
  • selected files
  • incoming transfer requests
  • device metadata
  • transfer history

Services and Methods

DevicePermissionService

File: lib/core/services/device_info_service.dart

Responsibility: fetch the local device name and Wi-Fi IP address.

Key methods:

  • getDeviceName() returns a readable device label.
  • getIpAddress() returns the current Wi-Fi IP address.

NetworkDiscoveryService

File: lib/core/services/network_discovery_services.dart

Responsibility: discover nearby devices using Bonsoir service broadcast and discovery.

Key methods:

  • startListening() initializes discovery and broadcasting.
  • _startBroadcast() advertises the current device on _proxync._tcp.
  • _startDiscovery() listens for Bonsoir discovery events.
  • _registerService() adds resolved devices to the local cache.
  • _removeService() removes devices that are no longer available.
  • stopListening() stops discovery, clears the cache, and resets state.

TransferService

File: lib/core/services/transfer_service.dart

Responsibility: accept incoming socket connections and save received files.

Key methods:

  • startServer() binds the local server socket on port 45678.
  • _handleConnection() processes metadata and file payloads from a client.
  • acceptTransfer() confirms the request, receives the file stream, and writes it to storage.
  • _finalizeFile() closes the sink, updates saved path, and records successful history.
  • declineTransfer() sends a decline response and cleans up the session.
  • stopServer() shuts down all active sessions and closes the socket server.
  • _getProxyncDirectory() resolves the save location for received files.
  • _tryGetPublicDownloadDir() attempts to save into the public Downloads/Proxync folder on Android.

FileSenderService

File: lib/core/services/file_sender_service.dart

Responsibility: send metadata and file bytes to a peer over a socket.

Key methods:

  • sendFile() connects to the target peer, sends metadata, waits for approval, and streams file data.
  • cancel() aborts an in-progress transfer.

FilePickerService

Responsibility: open the file picker and return the selected file.

Used by the file picker provider to build the Send tab file list.

HistoryNotifier

File: lib/features/history/provider/history_provider.dart

Responsibility: track transfer history and persist it locally.

Key methods:

  • addSent() records a sent transfer.
  • addReceived() records a received transfer.
  • clearAll() removes all stored history.

IncomingTransferNotifier

File: lib/features/receive/provider/incoming_transfer_provider.dart

Responsibility: manage the queue of incoming transfer requests.

Key methods:

  • addRequest() adds a new incoming request.
  • removeRequest() removes a request from the list.
  • updateStatus() updates the transfer state.
  • updateProgress() updates progress during file reception.
  • setSavedPath() stores the final file path.

Project Structure

lib/
	core/
		models/
		providers/
		route/
		services/
		widgets/
	features/
		send/
		receive/
		history/
		settings/

Notes

  • The app is designed for local network sharing, not internet-based transfers.
  • File reception is optimized for Android storage behavior and may fall back to app storage when public Downloads access is not available.
  • Nearby device discovery depends on both devices being visible on the same network.

Useful Commands

flutter pub get
flutter run
flutter test
flutter build apk

About

Local network file sharing app build with flutter

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages