Exemplos de Recursos Desktop Android Kotlin

Exemplos de recursos desktop Android Kotlin incluindo caixas de diálogo de arquivos, caixas de mensagem e bandeja do sistema

💻 Caixas de Mensagem kotlin

🟢 simple ⭐⭐⭐

Mostrar diálogos de alerta, prompts de confirmação, mensagens toast e snackbar

⏱️ 20 min 🏷️ kotlin, android, ui, dialogs
Prerequisites: Basic Kotlin, Android SDK
// Android Kotlin Message Box Examples
// Using AlertDialog, Toast, and Snackbar

import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.widget.EditText
import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View

// 1. Alert Dialogs
class AlertDialogHelper(private val activity: AppCompatActivity) {

    // Simple alert dialog
    fun showAlert(title: String, message: String) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("OK") { dialog, which ->
                println("OK clicked")
            }
            .show()
    }

    // Alert with callback
    fun showAlertWithCallback(
                    title: String,
                    message: String,
                    onOkClicked: () -> Unit
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("OK") { dialog, which ->
                onOkClicked()
            }
            .show()
    }

    // Confirmation dialog
    fun showConfirmDialog(
                    title: String,
                    message: String,
                    onConfirm: () -> Unit,
                    onCancel: () -> Unit = {}
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("Yes") { dialog, which ->
                onConfirm()
            }
            .setNegativeButton("No") { dialog, which ->
                onCancel()
            }
            .show()
    }

    // Dialog with icon
    fun showAlertWithIcon(
                    title: String,
                    message: String,
                    iconId: Int
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setIcon(iconId)
            .setPositiveButton("OK", null)
            .show()
    }

    // Dialog with neutral button
    fun showThreeButtonDialog(
                    title: String,
                    message: String,
                    onPositive: () -> Unit = {},
                    onNegative: () -> Unit = {},
                    onNeutral: () -> Unit = {}
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("Yes") { _, _ -> onPositive() }
            .setNegativeButton("No") { _, _ -> onNegative() }
            .setNeutralButton("Cancel") { _, _ -> onNeutral() }
            .show()
    }
}

// 2. Input Dialogs
class InputDialogHelper(private val activity: AppCompatActivity) {

    // Single input dialog
    fun showInputDialog(
                    title: String,
                    hint: String,
                    onConfirm: (String) -> Unit
    ) {
        val input = EditText(activity)
        input.hint = hint

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(input)
            .setPositiveButton("OK") { dialog, which ->
                val text = input.text.toString()
                onConfirm(text)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Multi-input dialog
    fun showMultiInputDialog(
                    title: String,
                    fields: List<InputField>,
                    onConfirm: (Map<String, String>) -> Unit
    ) {
        val container = activity.layoutInflater
            .inflate(android.R.layout.select_dialog_multiselect, null) as ViewGroup

        val inputs = mutableMapOf<String, EditText>()

        for (field in fields) {
            val layout = activity.layoutInflater.inflate(
                android.R.layout.simple_list_item_1,
                container,
                false
            ) as ViewGroup

            val label = EditText(activity)
            label.hint = field.hint
            label.inputType = field.inputType

            container.addView(label)
            inputs[field.key] = label
        }

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(container)
            .setPositiveButton("OK") { _, _ ->
                val values = inputs.mapValues { it.text.toString() }
                onConfirm(values)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Password input dialog
    fun showPasswordDialog(
                    title: String,
                    hint: String = "Enter password",
                    onConfirm: (String) -> Unit
    ) {
        val input = EditText(activity)
        input.hint = hint
        input.inputType = android.text.InputType.TYPE_CLASS_TEXT or
                         android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(input)
            .setPositiveButton("OK") { _, _ ->
                onConfirm(input.text.toString())
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Data class for input field
    data class InputField(
        val key: String,
        val hint: String,
        val inputType: Int = android.text.InputType.TYPE_CLASS_TEXT
    )
}

import android.view.ViewGroup

// 3. List Dialogs
class ListDialogHelper(private val activity: AppCompatActivity) {

    // Single choice list
    fun showSingleChoiceList(
                    title: String,
                    items: List<String>,
                    onSelected: (Int) -> Unit
    ) {
        var selectedItem = 0

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setSingleChoiceItems(items.toTypedArray(), selectedItem) { dialog, which ->
                selectedItem = which
            }
            .setPositiveButton("OK") { dialog, which ->
                onSelected(selectedItem)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Multi-choice list
    fun showMultiChoiceList(
                    title: String,
                    items: List<String>,
                    onSelected: (Set<Int>) -> Unit
    ) {
        val selectedItems = mutableSetOf<Int>()

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMultiChoiceItems(items.toTypedArray(), null) { dialog, which, isChecked ->
                if (isChecked) {
                    selectedItems.add(which)
                } else {
                    selectedItems.remove(which)
                }
            }
            .setPositiveButton("OK") { dialog, which ->
                onSelected(selectedItems)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Simple list dialog
    fun showListDialog(
                    title: String,
                    items: List<String>,
                    onSelected: (String) -> Unit
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setItems(items.toTypedArray()) { dialog, which ->
                onSelected(items[which])
            }
            .show()
    }
}

// 4. Toast Messages
class ToastHelper(private val context: Context) {

    // Short toast
    fun showShort(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
    }

    // Long toast
    fun showLong(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_LONG).show()
    }

    // Custom duration toast
    fun showCustom(message: String, durationMs: Int) {
        val toast = Toast.makeText(context, message, Toast.LENGTH_SHORT)
        toast.duration = durationMs
        toast.show()
    }

    // Toast with position
    fun showWithPosition(
                    message: String,
                    gravity: Int,
                    xOffset: Int,
                    yOffset: Int
    ) {
        val toast = Toast.makeText(context, message, Toast.LENGTH_SHORT)
        toast.setGravity(gravity, xOffset, yOffset)
        toast.show()
    }

    // Custom view toast
    fun showCustomView(message: String) {
        val inflater = LayoutInflater.from(context)
        val layout = inflater.inflate(android.R.layout.simple_list_item_1, null)

        // Assuming there's a TextView in the layout
        // val textView = layout.findViewById<TextView>(android.R.id.text1)
        // textView.text = message

        val toast = Toast(context)
        toast.view = layout
        toast.duration = Toast.LENGTH_SHORT
        toast.show()
    }
}

// 5. Snackbar
class SnackbarHelper {

    // Show simple snackbar
    fun show(view: View, message: String) {
        Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show()
    }

    // Show long snackbar
    fun showLong(view: View, message: String) {
        Snackbar.make(view, message, Snackbar.LENGTH_LONG).show()
    }

    // Snackbar with action
    fun showWithAction(
                    view: View,
                    message: String,
                    actionText: String,
                    onActionClicked: () -> Unit
    ) {
        Snackbar.make(view, message, Snackbar.LENGTH_LONG)
            .setAction(actionText) {
                onActionClicked()
            }
            .show()
    }

    // Indefinite snackbar
    fun showIndefinite(view: View, message: String) {
        Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
            .setAction("Dismiss") { }
            .show()
    }

    // Custom snackbar with callback
    fun showWithCallback(
                    view: View,
                    message: String,
                    onDismissed: () -> Unit
    ) {
        val snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT)

        snackbar.addCallback(object : Snackbar.Callback() {
            override fun onDismissed(transientBottomBar: Snackbar, event: Int) {
                onDismissed()
            }
        })

        snackbar.show()
    }

    // Snackbar with custom styling
    fun showStyled(view: View, message: String, backgroundColor: Int) {
        val snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT)

        snackbar.view.setBackgroundColor(backgroundColor)
        snackbar.show()
    }
}

// 6. Progress Dialogs
class ProgressDialogHelper(private val activity: AppCompatActivity) {

    // Simple progress dialog
    fun showProgressDialog(title: String, message: String): AlertDialog {
        val builder = AlertDialog.Builder(activity)

        val inflater = activity.layoutInflater
        val dialogView = inflater.inflate(android.R.layout.select_dialog_item, null)

        builder.setTitle(title)
            .setMessage(message)
            .setView(dialogView)
            .setCancelable(false)

        val dialog = builder.create()
        dialog.show()

        return dialog
    }

    // Indeterminate progress
    fun showIndeterminateProgress(title: String, message: String): AlertDialog {
        return showProgressDialog(title, message)
    }

    // Horizontal progress dialog
    fun showHorizontalProgress(
                    title: String,
                    message: String,
                    max: Int
    ): AlertDialog {
        val builder = AlertDialog.Builder(activity)

        val progressBar = android.widget.ProgressBar(activity, null, android.R.attr.progressBarStyleHorizontal)
        progressBar.max = max

        builder.setTitle(title)
            .setView(progressBar)
            .setCancelable(false)

        val dialog = builder.create()
        dialog.show()

        return dialog
    }
}

// Main demonstration
fun demonstrateMessageBoxes(activity: AppCompatActivity) {
    println("=== Android Kotlin Message Box Examples ===\n")

    // 1. Alert dialogs
    println("--- 1. Alert Dialogs ---")
    val alertDialogHelper = AlertDialogHelper(activity)

    alertDialogHelper.showAlert("Information", "This is an alert dialog")
    alertDialogHelper.showAlertWithCallback("Notice", "Operation completed") {
        println("Callback executed")
    }

    alertDialogHelper.showConfirmDialog(
        "Confirm",
        "Are you sure you want to continue?",
        onConfirm = { println("User confirmed") },
        onCancel = { println("User cancelled") }
    )

    // 2. Input dialogs
    println("\n--- 2. Input Dialogs ---")
    val inputDialogHelper = InputDialogHelper(activity)

    inputDialogHelper.showInputDialog("Enter Name", "Name") { name ->
        println("Entered name: $name")
    }

    inputDialogHelper.showPasswordDialog("Password") { password ->
        println("Password entered: ${password.length} chars")
    }

    // 3. List dialogs
    println("\n--- 3. List Dialogs ---")
    val listDialogHelper = ListDialogHelper(activity)

    val items = listOf("Option 1", "Option 2", "Option 3", "Option 4")

    listDialogHelper.showSingleChoiceList("Choose an option", items) { index ->
        println("Selected: ${items[index]}")
    }

    listDialogHelper.showListDialog("Select item", items) { item ->
        println("Selected: $item")
    }

    // 4. Toast messages
    println("\n--- 4. Toast Messages ---")
    val toastHelper = ToastHelper(activity)

    toastHelper.showShort("Short toast message")
    toastHelper.showLong("Long toast message")
    toastHelper.showWithPosition(
        "Positioned toast",
        android.view.Gravity.BOTTOM or android.view.Gravity.END,
        0,
        100
    )

    // 5. Snackbar
    println("\n--- 5. Snackbar ---")
    // Note: Snackbar requires a View as anchor
    println("Snackbar examples:")
    println("  - show(): Simple snackbar")
    println("  - showLong(): Long duration snackbar")
    println("  - showWithAction(): With action button")
    println("  - showIndefinite(): Until dismissed")
    println("  - showStyled(): Custom styling")

    // 6. Progress dialogs
    println("\n--- 6. Progress Dialogs ---")
    val progressDialogHelper = ProgressDialogHelper(activity)

    val progressDialog = progressDialogHelper.showIndeterminateProgress(
        "Loading",
        "Please wait..."
    )

    // Simulate loading
    activity.runOnUiThread {
        // In real app, dismiss when operation completes
        // progressDialog.dismiss()
    }

    println("\n=== All Message Box Examples Completed ===")
}

💻 Caixas de Diálogo de Arquivo kotlin

🟡 intermediate ⭐⭐⭐⭐

Abrir seletor de arquivos, caixa de diálogo salvar e seleção de diretório usando Storage Access Framework

⏱️ 30 min 🏷️ kotlin, android, ui, dialogs
Prerequisites: Intermediate Kotlin, Android SDK
// Android Kotlin File Dialog Examples
// Using Storage Access Framework and Intent

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.DocumentsContract
import android.provider.OpenableColumns
import android.content.ContentResolver
import android.database.Cursor
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity

// 1. Open File Dialog
class OpenFileDialogHelper(private val activity: AppCompatActivity) {

    // Create open file launcher
    private val openFileLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.also { uri ->
                handleFileSelected(uri)
            }
        }
    }

    // Open single file
    fun openFile(mimeType: String = "*/*") {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = mimeType
            putExtra(Intent.EXTRA_TITLE, "Select a file")
        }

        openFileLauncher.launch(intent)
    }

    // Open multiple files
    private val openMultipleFilesLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.let { intent ->
                val clipData = intent.clipData

                if (clipData != null) {
                    for (i in 0 until clipData.itemCount) {
                        val uri = clipData.getItemAt(i).uri
                        handleFileSelected(uri)
                    }
                } else {
                    intent.data?.also { uri ->
                        handleFileSelected(uri)
                    }
                }
            }
        }
    }

    fun openMultipleFiles(mimeType: String = "*/*") {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = mimeType
            putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
        }

        openMultipleFilesLauncher.launch(intent)
    }

    // Open specific file types
    fun openImage() {
        openFile("image/*")
    }

    fun openPdf() {
        openFile("application/pdf")
    }

    fun openTextFile() {
        openFile("text/*")
    }

    // Handle selected file
    private fun handleFileSelected(uri: Uri) {
        val fileName = getFileName(uri)
        val fileSize = getFileSize(uri)

        println("File selected: $fileName")
        println("Size: $fileSize bytes")
        println("URI: $uri")

        // Read file content
        val content = readFileContent(uri)
        println("Content preview: ${content?.take(100)}...")
    }

    // Get file name
    private fun getFileName(uri: Uri): String? {
        var result: String? = null

        if (uri.scheme == "content") {
            val cursor: Cursor? = activity.contentResolver.query(
                uri,
                null,
                null,
                null,
                null
            )

            cursor?.use {
                if (it.moveToFirst()) {
                    val index = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                    if (index >= 0) {
                        result = it.getString(index)
                    }
                }
            }
        }

        if (result == null) {
            result = uri.path
            val cut = result?.lastIndexOf('/')
            if (cut != -1) {
                result = result?.substring(cut!! + 1)
            }
        }

        return result
    }

    // Get file size
    private fun getFileSize(uri: Uri): Long {
        val cursor: Cursor? = activity.contentResolver.query(
            uri,
            arrayOf(OpenableColumns.SIZE),
            null,
            null,
            null
        )

        cursor?.use {
            if (it.moveToFirst()) {
                val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE)
                if (sizeIndex >= 0 && !it.isNull(sizeIndex)) {
                    return it.getLong(sizeIndex)
                }
            }
        }

        return 0L
    }

    // Read file content
    private fun readFileContent(uri: Uri): String? {
        return try {
            activity.contentResolver.openInputStream(uri)?.bufferedReader()?.use { it.readText() }
        } catch (e: Exception) {
            println("Error reading file: ${e.message}")
            null
        }
    }
}

// 2. Save File Dialog
class SaveFileDialogHelper(private val activity: AppCompatActivity) {

    private val saveFileLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.also { uri ->
                handleFileSaved(uri)
            }
        }
    }

    // Create new file
    fun createFile(fileName: String, mimeType: String = "text/plain") {
        val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = mimeType
            putExtra(Intent.EXTRA_TITLE, fileName)
        }

        saveFileLauncher.launch(intent)
    }

    // Save text content
    fun saveTextFile(fileName: String, content: String) {
        val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "text/plain"
            putExtra(Intent.EXTRA_TITLE, fileName)
        }

        saveFileLauncher.launch(Intent.createChooser(intent, "Save file"))
    }

    // Save image
    fun saveImageFile(fileName: String) {
        createFile(fileName, "image/png")
    }

    // Handle file saved
    private fun handleFileSaved(uri: Uri) {
        // Take persistable permission
        val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                         Intent.FLAG_GRANT_WRITE_URI_PERMISSION

        activity.contentResolver.takePersistableUriPermission(uri, takeFlags)

        println("File saved: $uri")

        // Write content to file
        try {
            activity.contentResolver.openOutputStream(uri)?.use { outputStream ->
                val content = "Sample content written at ${java.util.Date()}"
                outputStream.write(content.toByteArray())
            }

            println("Content written successfully")
        } catch (e: Exception) {
            println("Error writing file: ${e.message}")
        }
    }

    // Write bytes to file
    fun writeToFile(uri: Uri, data: ByteArray): Boolean {
        return try {
            activity.contentResolver.openOutputStream(uri)?.use { outputStream ->
                outputStream.write(data)
                outputStream.flush()
            }

            true
        } catch (e: Exception) {
            println("Error writing: ${e.message}")
            false
        }
    }
}

// 3. Directory Selection
class DirectoryPickerHelper(private val activity: AppCompatActivity) {

    private val directoryPickerLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.also { uri ->
                handleDirectorySelected(uri)
            }
        }
    }

    // Open directory picker
    fun openDirectory() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
            putExtra(DocumentsContract.EXTRA_INITIAL_URI, null)
        }

        directoryPickerLauncher.launch(intent)
    }

    // Handle directory selected
    private fun handleDirectorySelected(uri: Uri) {
        // Take persistable permission
        val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                         Intent.FLAG_GRANT_WRITE_URI_PERMISSION

        activity.contentResolver.takePersistableUriPermission(uri, takeFlags)

        println("Directory selected: $uri")

        // List files in directory
        listFilesInDirectory(uri)
    }

    // List files in directory
    private fun listFilesInDirectory(directoryUri: Uri) {
        val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
            directoryUri,
            DocumentsContract.getDocumentId(directoryUri)
        )

        val cursor: Cursor? = activity.contentResolver.query(
            childrenUri,
            arrayOf(
                DocumentsContract.Document.COLUMN_DISPLAY_NAME,
                DocumentsContract.Document.COLUMN_MIME_TYPE
            ),
            null,
            null,
            null
        )

        cursor?.use {
            println("Files in directory:")
            while (it.moveToNext()) {
                val nameIndex = it.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME)
                val mimeIndex = it.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE)

                val name = it.getString(nameIndex)
                val mimeType = it.getString(mimeIndex)

                println("  - $name ($mimeType)")
            }
        }
    }

    // Create subdirectory
    fun createSubdirectory(parentUri: Uri, directoryName: String): Uri? {
        return try {
            val documentUri = DocumentsContract.createDocument(
                activity.contentResolver,
                parentUri,
                DocumentsContract.Document.MIME_TYPE_DIR,
                directoryName
            )

            documentUri
        } catch (e: Exception) {
            println("Error creating directory: ${e.message}")
            null
        }
    }
}

// 4. Advanced File Operations
class AdvancedFileOperations(private val activity: AppCompatActivity) {

    // Open file with custom filter
    fun openWithFilter(mimeTypes: List<String>) {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = if (mimeTypes.size == 1) mimeTypes[0] else "*/*"

            if (mimeTypes.size > 1) {
                putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
            }
        }

        activity.startActivityForResult(intent, 1001)
    }

    // Get file metadata
    fun getFileMetadata(uri: Uri): FileMetadata? {
        val cursor: Cursor? = activity.contentResolver.query(
            uri,
            arrayOf(
                OpenableColumns.DISPLAY_NAME,
                OpenableColumns.SIZE,
                OpenableColumns.MIME_TYPE
            ),
            null,
            null,
            null
        )

        return cursor?.use {
            if (it.moveToFirst()) {
                val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE)
                val mimeIndex = it.getColumnIndex(OpenableColumns.MIME_TYPE)

                FileMetadata(
                    name = it.getString(nameIndex),
                    size = it.getLong(sizeIndex),
                    mimeType = it.getString(mimeIndex)
                )
            } else {
                null
            }
        }
    }

    // File metadata data class
    data class FileMetadata(
        val name: String,
        val size: Long,
        val mimeType: String
    )
}

// 5. Recent Documents
class RecentDocuments(private val activity: AppCompatActivity) {

    // Get recent files
    fun getRecentDocuments(): List<Uri> {
        val recentUris = mutableListOf<Uri>()

        // Query recent documents
        val projection = arrayOf(
            OpenableColumns.DISPLAY_NAME,
            OpenableColumns.DATE_MODIFIED
        )

        val cursor: Cursor? = activity.contentResolver.query(
            android.provider.MediaStore.Files.getContentUri("external"),
            projection,
            null,
            null,
            "${OpenableColumns.DATE_MODIFIED} DESC LIMIT 10"
        )

        cursor?.use {
            val idIndex = it.getColumnIndex(android.provider.BaseColumns._ID)

            while (it.moveToNext()) {
                val id = it.getLong(idIndex)
                val contentUri = android.provider.MediaStore.Files.getContentUri("external", id)
                recentUris.add(contentUri)
            }
        }

        return recentUris
    }
}

// Main demonstration
fun demonstrateFileDialogs(activity: AppCompatActivity) {
    println("=== Android Kotlin File Dialog Examples ===\n")

    // 1. Open file dialog
    println("--- 1. Open File Dialog ---")
    val openDialogHelper = OpenFileDialogHelper(activity)

    println("Opening file dialog...")
    openDialogHelper.openFile()

    println("\nOpening image picker...")
    openDialogHelper.openImage()

    println("\nOpening multiple files...")
    openDialogHelper.openMultipleFiles()

    // 2. Save file dialog
    println("\n--- 2. Save File Dialog ---")
    val saveDialogHelper = SaveFileDialogHelper(activity)

    println("Creating new file...")
    saveDialogHelper.createFile("example.txt", "text/plain")

    println("\nSaving text file...")
    saveDialogHelper.saveTextFile("note.txt", "Sample content")

    // 3. Directory picker
    println("\n--- 3. Directory Picker ---")
    val directoryPicker = DirectoryPickerHelper(activity)

    println("Opening directory picker...")
    directoryPicker.openDirectory()

    // 4. Advanced operations
    println("\n--- 4. Advanced Operations ---")
    val advancedOps = AdvancedFileOperations(activity)

    println("Opening with multiple MIME type filters...")
    advancedOps.openWithFilter(listOf("image/*", "video/*", "audio/*"))

    // 5. Recent documents
    println("\n--- 5. Recent Documents ---")
    val recentDocs = RecentDocuments(activity)

    println("Getting recent documents...")
    val recent = recentDocs.getRecentDocuments()
    println("Found ${recent.size} recent documents")

    println("\n=== All File Dialog Examples Completed ===")
}

💻 Bandeja do Sistema (Notificações) kotlin

🟡 intermediate ⭐⭐⭐⭐

Exibir notificações na bandeja do sistema/barra de status com várias opções

⏱️ 30 min 🏷️ kotlin, android, notifications, ui
Prerequisites: Intermediate Kotlin, Android SDK
// Android Kotlin Notification Examples
// Using NotificationManager and NotificationCompat

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import android.graphics.BitmapFactory
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity

// 1. Basic Notification
class BasicNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "basic_channel"
        private const val NOTIFICATION_ID = 1001
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    // Create notification channel (required for Android O+)
    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Basic Notifications",
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                description = "Basic notification channel"
                enableLights(true)
                lightColor = Color.BLUE
            }

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Show simple notification
    fun showNotification(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Show notification with large text
    fun showNotificationWithLargeText(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setStyle(
                NotificationCompat.BigTextStyle()
                    .bigText(message)
            )
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }
}

// 2. Notification with Actions
class ActionNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "action_channel"
        private const val NOTIFICATION_ID = 1002
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Action Notifications",
                NotificationManager.IMPORTANCE_HIGH
            ).apply {
                description = "Notifications with action buttons"
            }

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Notification with action button
    fun showNotificationWithAction(
                    title: String,
                    message: String,
                    actionText: String,
                    actionIntent: PendingIntent
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .addAction(
                android.R.drawable.ic_menu_send,
                actionText,
                actionIntent
            )
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Multiple actions
    fun showNotificationWithMultipleActions(
                    title: String,
                    message: String,
                    actions: List<NotificationAction>
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_HIGH)

        actions.forEach { action ->
            builder.addAction(action.icon, action.title, action.pendingIntent)
        }

        builder.setAutoCancel(true)
        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Data class for notification action
    data class NotificationAction(
        val icon: Int,
        val title: String,
        val pendingIntent: PendingIntent
    )
}

// 3. Progress Notification
class ProgressNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "progress_channel"
        private const val NOTIFICATION_ID = 1003
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Progress Notifications",
                NotificationManager.IMPORTANCE_LOW
            )

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Show indeterminate progress
    fun showIndeterminateProgress(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setOngoing(true)
            .setProgress(0, 0, true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Show determinate progress
    fun showProgress(title: String, message: String, max: Int, progress: Int) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setOngoing(true)
            .setProgress(max, progress, false)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Update progress
    fun updateProgress(max: Int, progress: Int, message: String? = null) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle("Downloading")
            .setContentText(message ?: "$progress%")
            .setOngoing(true)
            .setProgress(max, progress, false)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Complete progress
    fun completeProgress(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setProgress(0, 0, false)
            .setOngoing(false)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }
}

// 4. Rich Notification with Image
class RichNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "rich_channel"
        private const val NOTIFICATION_ID = 1004
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Rich Notifications",
                NotificationManager.IMPORTANCE_HIGH
            ).apply {
                description = "Rich notifications with images"
            }

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Big picture notification
    fun showBigPictureNotification(
                    title: String,
                    message: String,
                    imageBitmap: android.graphics.Bitmap
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setLargeIcon(imageBitmap)
            .setStyle(
                NotificationCompat.BigPictureStyle()
                    .bigPicture(imageBitmap)
                    .bigLargeIcon(null)
            )
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Inbox style notification
    fun showInboxNotification(
                    title: String,
                    contentTitle: String,
                    lines: List<String>
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(contentTitle)
            .setStyle(
                NotificationCompat.InboxStyle()
                    .setSummaryText("${lines.size} new messages")
                    .addLine(lines[0])
            )
            .setPriority(NotificationCompat.PRIORITY_HIGH)

        // Add remaining lines
        for (i in 1 until minOf(lines.size, 5)) {
            builder.setStyle(
                NotificationCompat.InboxStyle()
                    .setSummaryText("${lines.size} new messages")
                    .addLine(lines[i])
            )
        }

        builder.setAutoCancel(true)
        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }
}

// 5. Notification Groups
class GroupNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "group_channel"
        private const val GROUP_ID = "notification_group"
        private const val SUMMARY_ID = 1005
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Group Notifications",
                NotificationManager.IMPORTANCE_HIGH
            )

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Show grouped notifications
    fun showGroupedNotifications(
                    notifications: List<GroupedNotification>
    ) {
        // Show individual notifications
        notifications.forEach { notification ->
            val builder = NotificationCompat.Builder(context, CHANNEL_ID)
                .setSmallIcon(android.R.drawable.ic_dialog_info)
                .setContentTitle(notification.title)
                .setContentText(notification.message)
                .setGroup(GROUP_ID)
                .setAutoCancel(true)

            notificationManager.notify(notification.id, builder.build())
        }

        // Show summary notification
        val summaryBuilder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle("Group Summary")
            .setContentText("${notifications.size} notifications")
            .setGroup(GROUP_ID)
            .setGroupSummary(true)
            .setAutoCancel(true)

        notificationManager.notify(SUMMARY_ID, summaryBuilder.build())
    }

    // Data class for grouped notification
    data class GroupedNotification(
        val id: Int,
        val title: String,
        val message: String
    )
}

// 6. Notification Manager
class UnifiedNotificationManager(private val context: Context) {

    private val basicHelper = BasicNotificationHelper(context)
    private val actionHelper = ActionNotificationHelper(context)
    private val progressHelper = ProgressNotificationHelper(context)
    private val richHelper = RichNotificationHelper(context)
    private val groupHelper = GroupNotificationHelper(context)

    // Show simple notification
    fun notify(title: String, message: String) {
        basicHelper.showNotification(title, message)
    }

    // Show notification with action
    fun notifyWithAction(
                    title: String,
                    message: String,
                    actionText: String,
                    actionIntent: PendingIntent
    ) {
        actionHelper.showNotificationWithAction(title, message, actionText, actionIntent)
    }

    // Show progress
    fun showProgress(title: String, message: String, max: Int, progress: Int) {
        progressHelper.showProgress(title, message, max, progress)
    }

    // Cancel all notifications
    fun cancelAll() {
        val manager = NotificationManagerCompat.from(context)
        manager.cancelAll()
    }

    // Cancel specific notification
    fun cancel(id: Int) {
        val manager = NotificationManagerCompat.from(context)
        manager.cancel(id)
    }
}

// Main demonstration
fun demonstrateSystemTray(context: Context, activity: AppCompatActivity) {
    println("=== Android Kotlin Notification Examples ===\n")

    // 1. Basic notifications
    println("--- 1. Basic Notifications ---")
    val basicHelper = BasicNotificationHelper(context)

    basicHelper.showNotification(
        "Basic Notification",
        "This is a simple notification"
    )

    basicHelper.showNotificationWithLargeText(
        "Long Notification",
        "This is a notification with a very long message that " +
        "should be displayed using the big text style in the notification drawer."
    )

    // 2. Action notifications
    println("\n--- 2. Action Notifications ---")
    val actionHelper = ActionNotificationHelper(context)

    // Create pending intent
    val intent = Intent(context, activity::class.java)
    val pendingIntent = PendingIntent.getActivity(
        context,
        0,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    actionHelper.showNotificationWithAction(
        "Action Notification",
        "Click to perform action",
        "Reply",
        pendingIntent
    )

    // 3. Progress notifications
    println("\n--- 3. Progress Notifications ---")
    val progressHelper = ProgressNotificationHelper(context)

    progressHelper.showIndeterminateProgress("Indeterminate", "Working...")

    // Simulate progress
    val max = 100
    for (i in 0..100 step 10) {
        progressHelper.updateProgress(max, i, "Download: $i%")
    }

    progressHelper.completeProgress("Complete", "Download finished!")

    // 4. Rich notifications
    println("\n--- 4. Rich Notifications ---")
    val richHelper = RichNotificationHelper(context)

    // Note: In real usage, you'd have actual bitmap
    println("Rich notification types:")
    println("  - Big picture style")
    println("  - Inbox style")
    println("  - Messaging style")

    // 5. Group notifications
    println("\n--- 5. Group Notifications ---")
    val groupHelper = GroupNotificationHelper(context)

    val notifications = listOf(
        GroupNotificationHelper.GroupedNotification(
            1,
            "Message 1",
            "First message"
        ),
        GroupNotificationHelper.GroupedNotification(
            2,
            "Message 2",
            "Second message"
        ),
        GroupNotificationHelper.GroupedNotification(
            3,
            "Message 3",
            "Third message"
        )
    )

    groupHelper.showGroupedNotifications(notifications)

    // 6. Unified manager
    println("\n--- 6. Unified Notification Manager ---")
    val unifiedManager = UnifiedNotificationManager(context)

    println("Unified manager provides:")
    println("  - notify(): Simple notifications")
    println("  - notifyWithAction(): With action buttons")
    println("  - showProgress(): Progress notifications")
    println("  - cancelAll(): Cancel all notifications")

    println("\n=== All Notification Examples Completed ===")
}