allgram Files - Enterprise-Grade File Management Platform

Build secure, scalable, and feature-rich file management applications with our comprehensive storage API. From simple file uploads to distributed IPFS storage, from basic SFS to advanced DFS with enterprise features.

allgram Files provides enterprise-level security, GDPR compliance, and seamless integration with popular platforms. Perfect for businesses, developers, and organizations requiring professional file management solutions.

Enterprise Security

E2EE, FIPS 140-2, GDPR compliant

Dual Storage

SFS & DFS, IPFS, chunked uploads

Developer Friendly

REST API, SDKs, comprehensive docs

  • Quick Start Guide
  • Node.js
    Server-side implementation with Express.js, file upload handling, and comprehensive API integration

  • Swift
    iOS native development with UIKit/SwiftUI, file management, and secure storage implementation

  • Kotlin
    Android development with Jetpack Compose, file operations, and P2P storage capabilities

  • Additional Resources
    Security, performance, API reference, and community support

  • Files Services
    Explore enterprise features, pricing, and integration options
  • Licensing
    Commercial licenses, compliance, and enterprise agreements
  • Full Documentation
    Complete API reference, tutorials, and best practices

Node.js Integration

Build robust file management applications with Node.js and Express.js. Our comprehensive API provides file upload handling, dual storage support (SFS/DFS), and enterprise-grade security features. Perfect for building scalable backend services and file management applications.

  • Full API Support: Complete REST API with SFS and DFS storage integration
  • Enterprise Security: E2EE, RSA-2048, AES-256-GCM encryption
  • Dual Storage: Simple File System (SFS) and Distributed File System (DFS)
  • Scalable Architecture: Built for high-load production environments
Explore Files Services

// allgram Files Node.js Integration Example
const express = require('express');
const multer = require('multer');
const crypto = require('crypto');
const axios = require('axios');
const fs = require('fs');

class allgramFilesClient {
    constructor(apiKey, baseUrl = 'https://api.allgram.best') {
        this.apiKey = apiKey;
        this.baseUrl = baseUrl;
        this.files = new Map();
        this.storageType = 'SFS'; // SFS or DFS
    }

    // Initialize file storage client
    async initializeStorage() {
        try {
            // Check user subscription for DFS access
            const userInfo = await this.getUserInfo();
            if (userInfo.isPremium || userInfo.isEnterprise) {
                this.storageType = 'DFS';
                console.log('✅ DFS storage enabled');
            } else {
                console.log('✅ SFS storage enabled');
            }
        } catch (error) {
            console.error('Failed to initialize storage:', error);
        }
    }

    // Upload file to SFS (Simple File System)
    async uploadToSFS(file, isTemporary = true) {
        try {
            const formData = new FormData();
            formData.append('uploadfiles', file);

            const endpoint = isTemporary ? 'file/upload/batch' : 'app-media/upload/batch';
            const response = await axios.post(`${this.baseUrl}/v1/${endpoint}`, formData, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'multipart/form-data'
                }
            });

            if (response.status === 200) {
                const uploadedFiles = response.data;
                uploadedFiles.forEach(fileData => {
                    this.files.set(fileData.id, { ...fileData, storage: 'SFS' });
                });
                console.log(`✅ File uploaded to SFS: ${file.name}`);
                return uploadedFiles;
            }
        } catch (error) {
            console.error('Failed to upload to SFS:', error.response?.data || error.message);
            throw error;
        }
    }

    // Upload file to DFS (Distributed File System) - Premium/Enterprise only
    async uploadToDFS(file) {
        if (this.storageType !== 'DFS') {
            throw new Error('DFS storage requires Premium or Enterprise subscription');
        }

        try {
            const formData = new FormData();
            formData.append('uploadfiles', file);

            const response = await axios.post(`${this.baseUrl}/v1/file/upload/batch`, formData, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'multipart/form-data'
                }
            });

            if (response.status === 200) {
                const uploadedFiles = response.data;
                uploadedFiles.forEach(fileData => {
                    this.files.set(fileData.id, { ...fileData, storage: 'DFS' });
                });
                console.log(`✅ File uploaded to DFS: ${file.name}`);
                return uploadedFiles;
            }
        } catch (error) {
            console.error('Failed to upload to DFS:', error.response?.data || error.message);
            throw error;
        }
    }

    // Chunked upload for large files
    async uploadLargeFile(file, chunkSize = 2 * 1024 * 1024) { // 2MB chunks
        try {
            const totalChunks = Math.ceil(file.size / chunkSize);
            const chunks = [];

            for (let i = 0; i < totalChunks; i++) {
                const start = i * chunkSize;
                const end = Math.min(start + chunkSize, file.size);
                const chunk = file.slice(start, end);
                chunks.push(chunk);
            }

            console.log(`📦 Uploading ${file.name} in ${totalChunks} chunks`);

            // Upload chunks sequentially
            for (let i = 0; i < chunks.length; i++) {
                const chunk = chunks[i];
                const formData = new FormData();
                formData.append('chunk', chunk);
                formData.append('chunkIndex', i);
                formData.append('totalChunks', totalChunks);
                formData.append('filename', file.name);

                const response = await axios.post(`${this.baseUrl}/v1/app-media/upload-chunks/`, formData, {
                    headers: {
                        'Authorization': `Bearer ${this.apiKey}`,
                        'Content-Type': 'multipart/form-data'
                    }
                });

                if (response.status === 200) {
                    console.log(`✅ Chunk ${i + 1}/${totalChunks} uploaded`);
                }
            }

            // Complete chunked upload
            const completeResponse = await axios.post(`${this.baseUrl}/v1/app-media/convert/upload-chunks/`, {
                filename: file.name,
                totalChunks: totalChunks
            }, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                }
            });

            if (completeResponse.status === 200) {
                console.log(`✅ Large file upload completed: ${file.name}`);
                return completeResponse.data;
            }
        } catch (error) {
            console.error('Failed to upload large file:', error.response?.data || error.message);
            throw error;
        }
    }

    // Get user files list
    async getUserFiles(version = 'v1') {
        try {
            const endpoint = this.storageType === 'DFS' ? 'files/uploaded' : 'files/uploaded';
            const response = await axios.get(`${this.baseUrl}/v1/${endpoint}`, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`
                }
            });

            if (response.status === 200) {
                const files = response.data;
                files.forEach(file => {
                    this.files.set(file.id, { ...file, storage: this.storageType });
                });
                console.log(`✅ Retrieved ${files.length} files from ${this.storageType}`);
                return files;
            }
        } catch (error) {
            console.error('Failed to get user files:', error.response?.data || error.message);
            throw error;
        }
    }

    // Delete file (move to trash for DFS)
    async deleteFile(fileId) {
        try {
            const file = this.files.get(fileId);
            if (!file) {
                throw new Error('File not found');
            }

            const endpoint = file.storage === 'DFS' ? 'file/remove' : 'file/remove';
            const response = await axios.delete(`${this.baseUrl}/v1/${endpoint}`, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`
                },
                data: { _id: fileId }
            });

            if (response.status === 200) {
                if (file.storage === 'DFS') {
                    console.log(`🗑️ File moved to trash: ${file.filename}`);
                } else {
                    this.files.delete(fileId);
                    console.log(`🗑️ File deleted: ${file.filename}`);
                }
                return response.data;
            }
        } catch (error) {
            console.error('Failed to delete file:', error.response?.data || error.message);
            throw error;
        }
    }

    // Recover file from DFS trash
    async recoverFile(fileId) {
        if (this.storageType !== 'DFS') {
            throw new Error('File recovery only available in DFS storage');
        }

        try {
            const response = await axios.post(`${this.baseUrl}/v1/file/recover`, {
                _id: fileId
            }, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                }
            });

            if (response.status === 200) {
                console.log(`✅ File recovered from trash: ${fileId}`);
                return response.data;
            }
        } catch (error) {
            console.error('Failed to recover file:', error.response?.data || error.message);
            throw error;
        }
    }

    // Get user information
    async getUserInfo() {
        try {
            const response = await axios.get(`${this.baseUrl}/v1/account/info`, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`
                }
            });

            if (response.status === 200) {
                return response.data;
            }
        } catch (error) {
            console.error('Failed to get user info:', error.response?.data || error.message);
            throw error;
        }
    }

    // Search files by name or type
    searchFiles(query) {
        const searchTerm = query.toLowerCase();
        const results = Array.from(this.files.values()).filter(file =>
            file.filename.toLowerCase().includes(searchTerm) ||
            file.type_file?.toLowerCase().includes(searchTerm)
        );

        console.log(`🔍 Found ${results.length} files matching "${query}"`);
        return results;
    }

    // Get file statistics
    getFileStats() {
        const stats = {
            total: this.files.size,
            byStorage: {
                SFS: 0,
                DFS: 0
            },
            byType: {}
        };

        this.files.forEach(file => {
            stats.byStorage[file.storage]++;
            const type = file.type_file || 'unknown';
            stats.byType[type] = (stats.byType[type] || 0) + 1;
        });

        return stats;
    }
}

// Usage example
const filesClient = new allgramFilesClient('your-api-key-here');

// Initialize storage
filesClient.initializeStorage();

// Upload file to SFS
const file = fs.createReadStream('./example.jpg');
filesClient.uploadToSFS(file, false)
    .then(result => {
        console.log('File uploaded successfully:', result);
    })
    .catch(error => {
        console.error('Upload failed:', error);
    });

// Upload large file with chunking
const largeFile = fs.createReadStream('./large-video.mp4');
filesClient.uploadLargeFile(largeFile)
    .then(result => {
        console.log('Large file uploaded successfully:', result);
    })
    .catch(error => {
        console.error('Large file upload failed:', error);
    });
                                    

Key Features & Benefits

Our Node.js integration provides enterprise-grade file management capabilities with minimal setup. Built on proven technologies like Express.js and multer, it offers exceptional performance and reliability for production applications.

  • Dual Storage Support: SFS for basic users, DFS for Premium/Enterprise
  • Security First: End-to-end encryption with industry-standard algorithms
  • Chunked Uploads: Handle large files efficiently with 2MB chunks
  • Scalability: Designed for high-concurrency file operations
View Licensing Options

Swift iOS Integration

Build native iOS file management applications with Swift and SwiftUI. Our iOS SDK provides seamless integration with UIKit and SwiftUI, file operations, and secure storage implementation. Perfect for creating professional iOS file management applications with modern design patterns.

  • Native iOS Support: Full SwiftUI and UIKit compatibility
  • File Management: Upload, download, organize, and search files
  • Secure Storage: Military-grade encryption for sensitive files
  • Modern Architecture: MVVM, Combine, and async/await support
Explore Files Services

// allgram Files Swift iOS Integration Example
import SwiftUI
import Combine
import CryptoKit
import PhotosUI

// MARK: - File Models
struct FileUpload: Codable, Identifiable {
    let id: String
    let filename: String
    let typeFile: String
    let size: Int
    let link: String
    let storage: String
    let creationDatetime: Date
    let isSecure: Bool

    enum CodingKeys: String, CodingKey {
        case id = "_id"
        case filename
        case typeFile = "type_file"
        case size
        case link
        case storage
        case creationDatetime = "creation_datetime"
        case isSecure = "is_secure"
    }
}

// MARK: - File Service
class allgramFilesService: ObservableObject {
    @Published var files: [FileUpload] = []
    @Published var isUploading = false
    @Published var uploadProgress: Double = 0.0

    private let baseURL = "https://api.allgram.best"
    private let apiKey: String
    private var storageType: String = "SFS"

    init(apiKey: String) {
        self.apiKey = apiKey
        setupFileService()
    }

    // MARK: - Service Setup
    private func setupFileService() {
        checkUserSubscription()
    }

    private func checkUserSubscription() {
        Task {
            do {
                let userInfo = try await getUserInfo()
                await MainActor.run {
                    if userInfo.isPremium || userInfo.isEnterprise {
                        self.storageType = "DFS"
                        print("✅ DFS storage enabled")
                    } else {
                        print("✅ SFS storage enabled")
                    }
                }
            } catch {
                print("❌ Failed to check subscription:", error)
            }
        }
    }

    // MARK: - File Upload
    func uploadFile(_ file: PhotosPickerItem) async throws -> FileUpload {
        await MainActor.run {
            self.isUploading = true
            self.uploadProgress = 0.0
        }

        do {
            let data = try await file.loadTransferable(type: Data.self)
            guard let data = data else {
                throw FileError.invalidData
            }

            // Create temporary file
            let tempURL = FileManager.default.temporaryDirectory
                .appendingPathComponent(UUID().uuidString)
                .appendingPathExtension("tmp")
            try data.write(to: tempURL)

            // Upload file
            let uploadedFile = try await uploadFileToServer(tempURL)

            await MainActor.run {
                self.files.append(uploadedFile)
                self.isUploading = false
                self.uploadProgress = 1.0
            }

            return uploadedFile
        } catch {
            await MainActor.run {
                self.isUploading = false
                self.uploadProgress = 0.0
            }
            throw error
        }
    }

    private func uploadFileToServer(_ fileURL: URL) async throws -> FileUpload {
        let endpoint = storageType == "DFS" ? "file/upload/batch" : "app-media/upload/batch"
        let url = URL(string: "\(baseURL)/v1/\(endpoint)")!

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

        let boundary = UUID().uuidString
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

        var body = Data()

        // Add file data
        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name="uploadfiles"; filename="\(fileURL.lastPathComponent)"\r\n".data(using: .utf8)!)
        body.append("Content-Type: application/octet-stream\r\n\r\n".data(using: .utf8)!)
        body.append(try Data(contentsOf: fileURL))
        body.append("\r\n".data(using: .utf8)!)

        body.append("--\(boundary)--\r\n".data(using: .utf8)!)

        request.httpBody = body

        let (data, response) = try await URLSession.shared.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw FileError.serverError
        }

        let uploadedFiles = try JSONDecoder().decode([FileUpload].self, from: data)
        return uploadedFiles.first ?? FileUpload(id: "", filename: "", typeFile: "", size: 0, link: "", storage: storageType, creationDatetime: Date(), isSecure: false)
    }

    // MARK: - File Management
    func getUserFiles() async throws {
        let endpoint = storageType == "DFS" ? "files/uploaded" : "files/uploaded"
        let url = URL(string: "\(baseURL)/v1/\(endpoint)")!

        var request = URLRequest(url: url)
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

        let (data, response) = try await URLSession.shared.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw FileError.serverError
        }

        let files = try JSONDecoder().decode([FileUpload].self, from: data)

        await MainActor.run {
            self.files = files
        }
    }

    func deleteFile(_ file: FileUpload) async throws {
        let endpoint = file.storage == "DFS" ? "file/remove" : "file/remove"
        let url = URL(string: "\(baseURL)/v1/\(endpoint)")!

        var request = URLRequest(url: url)
        request.httpMethod = "DELETE"
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let body = ["_id": file.id]
        request.httpBody = try JSONSerialization.data(withJSONObject: body)

        let (_, response) = try await URLSession.shared.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw FileError.serverError
        }

        if file.storage == "DFS" {
            print("🗑️ File moved to trash: \(file.filename)")
        } else {
            await MainActor.run {
                self.files.removeAll { $0.id == file.id }
            }
            print("🗑️ File deleted: \(file.filename)")
        }
    }

    // MARK: - Search Files
    func searchFiles(query: String) -> [FileUpload] {
        let searchTerm = query.lowercased()
        return files.filter { file in
            file.filename.lowercased().contains(searchTerm) ||
            file.typeFile.lowercased().contains(searchTerm)
        }
    }

    // MARK: - Utility Methods
    private func getUserInfo() async throws -> UserInfo {
        let url = URL(string: "\(baseURL)/v1/account/info")!

        var request = URLRequest(url: url)
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

        let (data, response) = try await URLSession.shared.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw FileError.serverError
        }

        return try JSONDecoder().decode(UserInfo.self, from: data)
    }
}

// MARK: - Supporting Models
struct UserInfo: Codable {
    let isPremium: Bool
    let isEnterprise: Bool

    enum CodingKeys: String, CodingKey {
        case isPremium = "is_premium"
        case isEnterprise = "is_enterprise"
    }
}

enum FileError: Error, LocalizedError {
    case invalidData
    case serverError
    case operationNotSupported

    var errorDescription: String? {
        switch self {
        case .invalidData:
            return "Invalid file data"
        case .serverError:
            return "Server error occurred"
        case .operationNotSupported:
            return "Operation not supported for current storage type"
        }
    }
}

// MARK: - SwiftUI Views
struct FilesListView: View {
    @StateObject private var filesService = allgramFilesService(apiKey: "your-api-key")
    @State private var searchText = ""
    @State private var showingFilePicker = false

    var body: some View {
        NavigationView {
            List {
                ForEach(filesService.files) { file in
                    FileRowView(file: file, filesService: filesService)
                }
            }
            .navigationTitle("Files")
            .searchable(text: $searchText, prompt: "Search files")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Upload") {
                        showingFilePicker = true
                    }
                }
            }
            .photosPicker(isPresented: $showingFilePicker, selection: .constant(nil), matching: .any)
            .onAppear {
                Task {
                    try? await filesService.getUserFiles()
                }
            }
        }
    }
}

struct FileRowView: View {
    let file: FileUpload
    let filesService: allgramFilesService

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack {
                Text(file.filename)
                    .font(.headline)
                Spacer()
                if file.isSecure {
                    Image(systemName: "lock.fill")
                        .foregroundColor(.green)
                }
            }
            Text(file.typeFile)
                .font(.subheadline)
                .foregroundColor(.secondary)
            Text("Size: \(ByteCountFormatter.string(fromByteCount: Int64(file.size), countStyle: .file))")
                .font(.caption)
                .foregroundColor(.secondary)
            Text("Storage: \(file.storage)")
                .font(.caption)
                .foregroundColor(.secondary)
        }
        .padding(.vertical, 4)
        .swipeActions {
            Button("Delete", role: .destructive) {
                Task {
                    try? await filesService.deleteFile(file)
                }
            }
        }
    }
}
                                    

iOS Development Features

Our Swift SDK leverages the latest iOS technologies including SwiftUI, Combine, and async/await. Built with modern iOS development patterns, it provides a seamless developer experience while maintaining high performance and security standards.

  • SwiftUI Integration: Native SwiftUI components and data binding
  • Combine Framework: Reactive programming with publishers and subscribers
  • Async/Await: Modern concurrency for better performance
  • PhotosPicker: Native iOS photo and file selection
View Licensing Options

Kotlin Android Integration

Build powerful Android file management applications with Kotlin and Jetpack Compose. Our Android SDK provides seamless integration with modern Android development tools, file operations, and P2P storage capabilities. Perfect for creating professional Android file management applications.

  • Jetpack Compose: Modern declarative UI toolkit
  • File Operations: Upload, download, organize, and search files
  • P2P Storage: Direct peer-to-peer file sharing capabilities
  • Android Architecture: MVVM, Repository pattern, and Coroutines
Explore Files Services

// allgram Files Kotlin Android Integration Example
package com.allgram.files

import android.util.Log
import androidx.compose.runtime.*
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import java.io.File
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec

// MARK: - Data Models
data class FileUpload(
    val id: String,
    val filename: String,
    val typeFile: String,
    val size: Int,
    val link: String,
    val storage: String,
    val creationDatetime: Long,
    val isSecure: Boolean = false
)

data class FileContent(
    val text: String? = null,
    val media: List<String>? = null,
    val poll: String? = null,
    val quote: QuoteData? = null
)

data class QuoteData(
    val messageId: String,
    val content: String,
    val author: String
)

// MARK: - File Service
class allgramFilesService(
    private val apiKey: String,
    private val baseUrl: String = "https://api.allgram.best"
) {
    private val client = OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build()

    private var storageType: String = "SFS"
    private val fileCallbacks = mutableListOf<(FileUpload) -> Unit>()
    private val uploadProgressCallbacks = mutableListOf<(Double) -> Unit>()

    // MARK: - Service Initialization
    suspend fun initializeStorage() {
        try {
            val userInfo = getUserInfo()
            storageType = if (userInfo.isPremium || userInfo.isEnterprise) "DFS" else "SFS"
            Log.d("allgramFiles", "✅ ${storageType} storage enabled")
        } catch (e: Exception) {
            Log.e("allgramFiles", "Failed to initialize storage", e)
        }
    }

    // MARK: - File Upload
    suspend fun uploadFile(file: File, isTemporary: Boolean = true): Result<FileUpload> = withContext(Dispatchers.IO) {
        try {
            val formData = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(
                    "uploadfiles",
                    file.name,
                    file.asRequestBody("application/octet-stream".toMediaType())
                )
                .build()

            val endpoint = if (isTemporary) "file/upload/batch" else "app-media/upload/batch"
            val request = Request.Builder()
                .url("$baseUrl/v1/$endpoint")
                .post(formData)
                .addHeader("Authorization", "Bearer $apiKey")
                .build()

            val response = client.newCall(request).execute()

            if (response.isSuccessful) {
                val responseBody = response.body?.string()
                val fileJson = JSONObject(responseBody ?: "")

                val uploadedFile = FileUpload(
                    id = fileJson.getString("_id"),
                    filename = fileJson.getString("filename"),
                    typeFile = fileJson.getString("type_file"),
                    size = fileJson.optInt("size", 0),
                    link = fileJson.getString("link"),
                    storage = storageType,
                    creationDatetime = fileJson.optLong("creation_datetime", System.currentTimeMillis() / 1000),
                    isSecure = fileJson.optBoolean("is_secure", false)
                )

                Log.d("allgramFiles", "✅ File uploaded to $storageType: ${file.name}")
                Result.success(uploadedFile)
            } else {
                Log.e("allgramFiles", "Failed to upload file: ${response.code}")
                Result.failure(Exception("Server error: ${response.code}"))
            }
        } catch (e: Exception) {
            Log.e("allgramFiles", "Exception uploading file", e)
            Result.failure(e)
        }
    }

    // MARK: - Upload to DFS (Premium/Enterprise only)
    suspend fun uploadToDFS(file: File): Result<FileUpload> = withContext(Dispatchers.IO) {
        if (storageType != "DFS") {
            return Result.failure(Exception("DFS storage requires Premium or Enterprise subscription"))
        }

        return uploadFile(file, false)
    }

    // MARK: - Chunked Upload for Large Files
    suspend fun uploadLargeFile(file: File, chunkSize: Int = 2 * 1024 * 1024): Result<FileUpload> = withContext(Dispatchers.IO) {
        try {
            val totalChunks = kotlin.math.ceil(file.length().toDouble() / chunkSize.toDouble()).toInt()
            Log.d("allgramFiles", "📦 Uploading ${file.name} in $totalChunks chunks")

            // Upload chunks sequentially
            for (i in 0 until totalChunks) {
                val start = i * chunkSize
                val end = minOf(start + chunkSize, file.length().toInt())
                val chunk = file.readBytes().slice(start until end)

                uploadChunk(chunk, i, totalChunks, file.name)

                val progress = (i + 1).toDouble() / totalChunks
                uploadProgressCallbacks.forEach { callback ->
                    callback(progress)
                }
            }

            // Complete chunked upload
            val uploadedFile = completeChunkedUpload(file.name, totalChunks)
            Log.d("allgramFiles", "✅ Large file upload completed: ${file.name}")
            Result.success(uploadedFile)
        } catch (e: Exception) {
            Log.e("allgramFiles", "Failed to upload large file", e)
            Result.failure(e)
        }
    }

    private suspend fun uploadChunk(chunk: ByteArray, index: Int, totalChunks: Int, filename: String) {
        val formData = MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart(
                "chunk",
                "chunk_$index",
                chunk.toRequestBody("application/octet-stream".toMediaType())
            )
            .addFormDataPart("chunkIndex", index.toString())
            .addFormDataPart("totalChunks", totalChunks.toString())
            .addFormDataPart("filename", filename)
            .build()

        val request = Request.Builder()
            .url("$baseUrl/v1/app-media/upload-chunks/")
            .post(formData)
            .addHeader("Authorization", "Bearer $apiKey")
            .build()

        val response = client.newCall(request).execute()

        if (response.isSuccessful) {
            Log.d("allgramFiles", "✅ Chunk ${index + 1}/$totalChunks uploaded")
        } else {
            throw Exception("Failed to upload chunk ${index + 1}")
        }
    }

    private suspend fun completeChunkedUpload(filename: String, totalChunks: Int): FileUpload {
        val requestBody = JSONObject().apply {
            put("filename", filename)
            put("totalChunks", totalChunks)
        }.toString()

        val request = Request.Builder()
            .url("$baseUrl/v1/app-media/convert/upload-chunks/")
            .post(requestBody.toRequestBody("application/json".toMediaType()))
            .addHeader("Authorization", "Bearer $apiKey")
            .build()

        val response = client.newCall(request).execute()

        if (response.isSuccessful) {
            val responseBody = response.body?.string()
            val fileJson = JSONObject(responseBody ?: "")

            return FileUpload(
                id = fileJson.getString("_id"),
                filename = fileJson.getString("filename"),
                typeFile = fileJson.getString("type_file"),
                size = fileJson.optInt("size", 0),
                link = fileJson.getString("link"),
                storage = storageType,
                creationDatetime = fileJson.optLong("creation_datetime", System.currentTimeMillis() / 1000),
                isSecure = fileJson.optBoolean("is_secure", false)
            )
        } else {
            throw Exception("Failed to complete chunked upload")
        }
    }

    // MARK: - File Management
    suspend fun getUserFiles(): Result<List<FileUpload>> = withContext(Dispatchers.IO) {
        try {
            val endpoint = if (storageType == "DFS") "files/uploaded" else "files/uploaded"
            val request = Request.Builder()
                .url("$baseUrl/v1/$endpoint")
                .addHeader("Authorization", "Bearer $apiKey")
                .build()

            val response = client.newCall(request).execute()

            if (response.isSuccessful) {
                val responseBody = response.body?.string()
                val filesArray = JSONObject(responseBody ?: "").getJSONArray("files")

                val files = mutableListOf<FileUpload>()
                for (i in 0 until filesArray.length()) {
                    val fileJson = filesArray.getJSONObject(i)
                    val file = FileUpload(
                        id = fileJson.getString("_id"),
                        filename = fileJson.getString("filename"),
                        typeFile = fileJson.getString("type_file"),
                        size = fileJson.optInt("size", 0),
                        link = fileJson.getString("link"),
                        storage = storageType,
                        creationDatetime = fileJson.optLong("creation_datetime", System.currentTimeMillis() / 1000),
                        isSecure = fileJson.optBoolean("is_secure", false)
                    )
                    files.add(file)
                }

                Log.d("allgramFiles", "✅ Retrieved ${files.size} files from $storageType")
                Result.success(files)
            } else {
                Log.e("allgramFiles", "Failed to get user files: ${response.code}")
                Result.failure(Exception("Server error: ${response.code}"))
            }
        } catch (e: Exception) {
            Log.e("allgramFiles", "Exception getting user files", e)
            Result.failure(e)
        }
    }

    // MARK: - Delete File
    suspend fun deleteFile(file: FileUpload): Result<Unit> = withContext(Dispatchers.IO) {
        try {
            val endpoint = if (file.storage == "DFS") "file/remove" else "file/remove"
            val requestBody = JSONObject().apply {
                put("_id", file.id)
            }.toString()

            val request = Request.Builder()
                .url("$baseUrl/v1/$endpoint")
                .delete(requestBody.toRequestBody("application/json".toMediaType()))
                .addHeader("Authorization", "Bearer $apiKey")
                .build()

            val response = client.newCall(request).execute()

            if (response.isSuccessful) {
                if (file.storage == "DFS") {
                    Log.d("allgramFiles", "🗑️ File moved to trash: ${file.filename}")
                } else {
                    Log.d("allgramFiles", "🗑️ File deleted: ${file.filename}")
                }
                Result.success(Unit)
            } else {
                Log.e("allgramFiles", "Failed to delete file: ${response.code}")
                Result.failure(Exception("Server error: ${response.code}"))
            }
        } catch (e: Exception) {
            Log.e("allgramFiles", "Exception deleting file", e)
            Result.failure(e)
        }
    }

    // MARK: - Recover File from DFS Trash
    suspend fun recoverFile(fileId: String): Result<Unit> = withContext(Dispatchers.IO) {
        if (storageType != "DFS") {
            return Result.failure(Exception("File recovery only available in DFS storage"))
        }

        try {
            val requestBody = JSONObject().apply {
                put("_id", fileId)
            }.toString()

            val request = Request.Builder()
                .url("$baseUrl/v1/file/recover")
                .post(requestBody.toRequestBody("application/json".toMediaType()))
                .addHeader("Authorization", "Bearer $apiKey")
                .build()

            val response = client.newCall(request).execute()

            if (response.isSuccessful) {
                Log.d("allgramFiles", "✅ File recovered from trash: $fileId")
                Result.success(Unit)
            } else {
                Log.e("allgramFiles", "Failed to recover file: ${response.code}")
                Result.failure(Exception("Server error: ${response.code}"))
            }
        } catch (e: Exception) {
            Log.e("allgramFiles", "Exception recovering file", e)
            Result.failure(e)
        }
    }

    // MARK: - Search Files
    fun searchFiles(files: List<FileUpload>, query: String): List<FileUpload> {
        val searchTerm = query.lowercase()
        return files.filter { file ->
            file.filename.lowercased().contains(searchTerm) ||
            file.typeFile.lowercased().contains(searchTerm)
        }
    }

    // MARK: - Utility Methods
    private suspend fun getUserInfo(): UserInfo {
        val request = Request.Builder()
            .url("$baseUrl/v1/account/info")
            .addHeader("Authorization", "Bearer $apiKey")
            .build()

        val response = client.newCall(request).execute()

        if (response.isSuccessful) {
            val responseBody = response.body?.string()
            val userJson = JSONObject(responseBody ?: "")

            return UserInfo(
                isPremium = userJson.optBoolean("is_premium", false),
                isEnterprise = userJson.optBoolean("is_enterprise", false)
            )
        } else {
            throw Exception("Failed to get user info: ${response.code}")
        }
    }

    // MARK: - Callbacks
    fun addFileCallback(callback: (FileUpload) -> Unit) {
        fileCallbacks.add(callback)
    }

    fun addUploadProgressCallback(callback: (Double) -> Unit) {
        uploadProgressCallbacks.add(callback)
    }

    fun removeFileCallback(callback: (FileUpload) -> Unit) {
        fileCallbacks.remove(callback)
    }

    fun removeUploadProgressCallback(callback: (Double) -> Unit) {
        uploadProgressCallbacks.remove(callback)
    }
}

// MARK: - Supporting Models
data class UserInfo(
    val isPremium: Boolean,
    val isEnterprise: Boolean
)

// MARK: - ViewModel
class FilesViewModel(
    private val filesService: allgramFilesService
) : ViewModel() {

    private val _files = MutableStateFlow<List<FileUpload>>(emptyList())
    val files: StateFlow<List<FileUpload>> = _files.asStateFlow()

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

    private val _uploadProgress = MutableStateFlow(0.0)
    val uploadProgress: StateFlow<Double> = _uploadProgress.asStateFlow()

    init {
        setupFilesService()
        loadFiles()
    }

    private fun setupFilesService() {
        filesService.addUploadProgressCallback { progress ->
            _uploadProgress.value = progress
        }
    }

    private fun loadFiles() {
        viewModelScope.launch {
            _isLoading.value = true
            try {
                val result = filesService.getUserFiles()
                result.onSuccess { files ->
                    _files.value = files
                }.onFailure { error ->
                    Log.e("FilesViewModel", "Failed to load files", error)
                }
            } finally {
                _isLoading.value = false
            }
        }
    }

    fun uploadFile(file: File) {
        viewModelScope.launch {
            _isLoading.value = true
            try {
                val result = filesService.uploadFile(file)
                result.onSuccess { uploadedFile ->
                    _files.value = _files.value + uploadedFile
                }.onFailure { error ->
                    Log.e("FilesViewModel", "Failed to upload file", error)
                }
            } finally {
                _isLoading.value = false
            }
        }
    }

    fun deleteFile(file: FileUpload) {
        viewModelScope.launch {
            val result = filesService.deleteFile(file)
            result.onSuccess {
                if (file.storage != "DFS") {
                    _files.value = _files.value.filter { it.id != file.id }
                }
            }.onFailure { error ->
                Log.e("FilesViewModel", "Failed to delete file", error)
            }
        }
    }

    fun searchFiles(query: String): List<FileUpload> {
        return filesService.searchFiles(_files.value, query)
    }
}

// MARK: - Compose UI
@Composable
fun FilesListScreen(
    viewModel: FilesViewModel = viewModel { FilesViewModel(allgramFilesService("your-api-key")) }
) {
    val files by viewModel.files.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()
    val uploadProgress by viewModel.uploadProgress.collectAsState()

    LazyColumn {
        items(files) { file ->
            FileItem(
                file = file,
                onDelete = { viewModel.deleteFile(file) }
            )
        }
    }

    if (isLoading) {
        CircularProgressIndicator()
    }

    if (uploadProgress > 0.0 && uploadProgress < 1.0) {
        LinearProgressIndicator(progress = uploadProgress)
    }
}

@Composable
fun FileItem(
    file: FileUpload,
    onDelete: () -> Unit
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = file.filename,
                    style = MaterialTheme.typography.h6
                )
                if (file.isSecure) {
                    Icon(
                        imageVector = Icons.Default.Lock,
                        contentDescription = "Secure File",
                        tint = Color.Green
                    )
                }
            }

            Text(
                text = file.typeFile,
                style = MaterialTheme.typography.body2,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )

            Text(
                text = "Size: ${file.size} bytes",
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )

            Text(
                text = "Storage: ${file.storage}",
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )

            Button(
                onClick = onDelete,
                colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red)
            ) {
                Text("Delete")
            }
        }
    }
}
                                    

Android Development Features

Our Kotlin SDK leverages the latest Android technologies including Jetpack Compose, Coroutines, and modern Android architecture patterns. Built with performance and developer experience in mind, it provides a robust foundation for building scalable file management applications.

  • Jetpack Compose: Modern declarative UI with Material Design 3
  • Coroutines: Asynchronous programming with structured concurrency
  • MVVM Architecture: Clean architecture with Repository pattern
  • File Operations: Comprehensive file management capabilities
View Licensing Options

Additional Resources & Next Steps

Ready to take your file management integration to the next level? Explore our comprehensive resources and advanced features to build enterprise-grade file applications with allgram.

Security & Compliance

Learn about our enterprise security features, GDPR compliance, and FIPS 140-2 certification.

Learn More →

Storage Solutions

Discover advanced storage options including SFS, DFS, IPFS, and enterprise solutions.

Learn More →

API Reference

Complete API documentation with examples, error codes, and best practices.

View Docs →

Community Support

Join our developer community for support, updates, and collaboration.

Join Community →