Membuat Aplikasi Dengan Fitur Kirim Pesan Via Whatsaap - Dart Flutter

Tutorial Flutter

Membuat aplikasi dengan fitur Kirim Pesan ke WhatsApp

Pada tutorial ini, kita akan belajar membuat aplikasi berbasis Flutter Web yang memungkinkan pengguna mengirim pesan langsung ke WhatsApp.

Tampilan dibuat modern dengan efek glassmorphism sehingga terlihat elegan dan profesional.

🎯 Tujuan Aplikasi

  • Input pesan
  • Tombol kirim ke WhatsApp
  • Validasi pesan
  • UI modern (gradient + glass effect)
  • Notifikasi interaktif

🧱 Struktur Dasar Program

1. Main Function

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

Ini adalah entry point aplikasi Flutter.

2. MaterialApp

MaterialApp(
  title: 'CMessege',
  debugShowCheckedModeBanner: false,
  theme: ThemeData(
    useMaterial3: true,
  ),
);
    

3. Stateful Widget

class AnonymousMessagePage extends StatefulWidget
    

Digunakan untuk mengatur state seperti input dan loading.

✏️ Mengelola Input

final TextEditingController _messageController = TextEditingController();
    

Digunakan untuk membaca input dari pengguna.

📱 Kirim ke WhatsApp

final encodedMessage = Uri.encodeComponent(message);
final whatsappUrl = 'https://wa.me/$_targetPhone?text=$encodedMessage';
    

Format: https://wa.me/NOMOR?text=PESAN

🎨 UI Design

Gradient

LinearGradient(
  colors: [Color(0xFF4A00E0), Color(0xFF2B0054)]
)
    

Glass Effect

color: Colors.white.withOpacity(0.15)
    

💡 UX Improvement

  • Loading indicator
  • Snackbar feedback
  • Auto clear input
  • Tap luar untuk menutup keyboard

🎯 Kesimpulan

Flutter Web memungkinkan kita membuat aplikasi modern tanpa backend, langsung terhubung ke WhatsApp dengan UI yang menarik.

💻 Source Code Lengkap

Salin dan gunakan kode di bawah ini untuk mencoba langsung project Flutter kamu

import 'package:flutter/material.dart';
import 'dart:html' as html;

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CMessege',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        brightness: Brightness.light,
        useMaterial3: true,
        scaffoldBackgroundColor: Colors.transparent,
      ),
      home: const AnonymousMessagePage(),
    );
  }
}

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

  @override
  State createState() => _AnonymousMessagePageState();
}

class _AnonymousMessagePageState extends State {
  final TextEditingController _messageController = TextEditingController();
  bool _isSending = false;

  // Nomor WhatsApp tujuan (sudah di-set ke nomor Anda)
  final String _targetPhone = '6281646881706';

  @override
  void dispose() {
    _messageController.dispose();
    super.dispose();
  }

  void _sendToWhatsApp() async {
    final message = _messageController.text.trim();

    if (message.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Pesan tidak boleh kosong!'),
          behavior: SnackBarBehavior.floating,
          backgroundColor: Colors.redAccent,
          duration: Duration(seconds: 2),
        ),
      );
      return;
    }

    setState(() {
      _isSending = true;
    });

    final encodedMessage = Uri.encodeComponent(message);
    final whatsappUrl = 'https://wa.me/$_targetPhone?text=$encodedMessage';

    await Future.delayed(const Duration(milliseconds: 300));

    try {
      html.window.open(whatsappUrl, '_blank');

      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Mengirim pesan... 📱'),
            behavior: SnackBarBehavior.floating,
            backgroundColor: Color(0xFF2A7C6F),
            duration: Duration(seconds: 2),
          ),
        );
        _messageController.clear();
      }
    } catch (e) {
      if (mounted) {
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(28)),
            title: const Text('Pop-up diblokir?'),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text('Browser Anda memblokir tab baru.'),
                const SizedBox(height: 12),
                const Text('Klik tautan berikut untuk membuka WhatsApp:'),
                const SizedBox(height: 12),
                SelectableText(whatsappUrl,
                    style: const TextStyle(color: Colors.blue)),
              ],
            ),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Text('Tutup'),
              ),
              ElevatedButton(
                onPressed: () {
                  html.window.location.href = whatsappUrl;
                  Navigator.pop(context);
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: const Color(0xFF25D366),
                  foregroundColor: Colors.white,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20)),
                ),
                child: const Text('Buka Manual'),
              ),
            ],
          ),
        );
      }
    } finally {
      if (mounted) {
        setState(() {
          _isSending = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        title: const Text(
          'CMassage.fans',
          style: TextStyle(
            fontWeight: FontWeight.w600,
            fontSize: 20,
            letterSpacing: -0.3,
            color: Colors.white,
          ),
        ),
        centerTitle: true,
        elevation: 0,
        backgroundColor: Colors.transparent,
        toolbarHeight: 90,
        flexibleSpace: SafeArea(
          child: Padding(
            padding: const EdgeInsets.only(top: 12),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const SizedBox(width: 8),
              ],
            ),
          ),
        ),
      ),
      body: GestureDetector(
        onTap: () => FocusScope.of(context).unfocus(),
        child: Container(
          decoration: const BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                Color(0xFF4A00E0), // Ungu tua
                Color(0xFF2B0054), // Ungu kehitaman
                Color(0xFF1A0033), // Hitam keunguan
              ],
            ),
          ),
          child: SafeArea(
            child: Center(
              child: SingleChildScrollView(
                padding:
                    const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    // Liquid Glass Card
                    Container(
                      padding: const EdgeInsets.all(28),
                      decoration: BoxDecoration(
                        color: Colors.white.withValues(alpha: 0.15),
                        borderRadius: BorderRadius.circular(48),
                        border: Border.all(
                          color: Colors.white.withValues(alpha: 0.25),
                          width: 1.5,
                        ),
                        boxShadow: [
                          BoxShadow(
                            color: Colors.black.withValues(alpha: 0.2),
                            blurRadius: 30,
                            offset: const Offset(0, 10),
                            spreadRadius: -5,
                          ),
                        ],
                      ),
                      child: Column(
                        children: [
                          const SizedBox(height: 20),
                          const Text(
                            'Kirim Pesan',
                            style: TextStyle(
                              fontSize: 24,
                              fontWeight: FontWeight.bold,
                              color: Colors.white,
                            ),
                          ),
                          const SizedBox(height: 8),
                          Text(
                            'Kirim pesan langsung ke idola kalian',
                            textAlign: TextAlign.center,
                            style: TextStyle(
                              fontSize: 13,
                              color: Colors.white.withValues(alpha: 0.85),
                            ),
                          ),
                          const SizedBox(height: 32),

                          // Input Pesan
                          Container(
                            decoration: BoxDecoration(
                              color: Colors.white.withValues(alpha: 0.2),
                              borderRadius: BorderRadius.circular(32),
                              border: Border.all(
                                color: Colors.white.withValues(alpha: 0.3),
                                width: 1,
                              ),
                            ),
                            child: TextField(
                              controller: _messageController,
                              maxLines: 5,
                              minLines: 3,
                              style: const TextStyle(
                                color: Colors.white,
                                fontSize: 16,
                                fontWeight: FontWeight.w500,
                              ),
                              decoration: InputDecoration(
                                hintText: 'Ketik pesan di sini...',
                                hintStyle: TextStyle(
                                  color: Colors.white.withValues(alpha: 0.6),
                                  fontSize: 15,
                                ),
                                border: InputBorder.none,
                                contentPadding: const EdgeInsets.symmetric(
                                    horizontal: 22, vertical: 20),
                              ),
                              cursorColor: Colors.white,
                            ),
                          ),

                          const SizedBox(height: 32),

                          // Tombol Kirim
                          SizedBox(
                            width: double.infinity,
                            child: ElevatedButton(
                              onPressed: _isSending ? null : _sendToWhatsApp,
                              style: ElevatedButton.styleFrom(
                                backgroundColor: Colors.white,
                                foregroundColor: const Color(0xFF4A00E0),
                                elevation: 0,
                                padding:
                                    const EdgeInsets.symmetric(vertical: 18),
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(40),
                                ),
                                textStyle: const TextStyle(
                                  fontSize: 18,
                                  fontWeight: FontWeight.bold,
                                  letterSpacing: 0.5,
                                ),
                              ),
                              child: _isSending
                                  ? const SizedBox(
                                      height: 24,
                                      width: 24,
                                      child: CircularProgressIndicator(
                                        strokeWidth: 2.5,
                                        valueColor:
                                            AlwaysStoppedAnimation(
                                          Color(0xFF4A00E0),
                                        ),
                                      ),
                                    )
                                  : const Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.center,
                                      children: [
                                        Icon(Icons.send, size: 22),
                                        SizedBox(width: 8),
                                        Text('Kirim via WhatsApp'),
                                      ],
                                    ),
                            ),
                          ),

                          const SizedBox(height: 20),

                          // Catatan anonim
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              const Icon(Icons.security,
                                  size: 14, color: Colors.white70),
                              const SizedBox(width: 6),
                              Text(
                                'Pesan dikirim langsung ke idol, caca ardiansyah',
                                style: TextStyle(
                                  fontSize: 11,
                                  color: Colors.white.withValues(alpha: 0.7),
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),

                    const SizedBox(height: 24),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Komentar

Postingan populer dari blog ini

membuat aplikasi sederhana dengan konsep CRUD - ngawiflix

Belajar Flutter Biar Gak Cupu: Bikin App Ada Foto + Tombol SnackBar