LOGIN PAGE

πŸ–₯️Ngoding LoginPage Kekinian di ZappRunπŸš€

Halo gengs! Kali ini gue mau sharing gimana cara bikin login page kece di Flutter lewat ZappRun.
Buat lo yang suka coding tapi pengen hasil cepet tanpa ribet, ZappRun tuh kayak sahabat sejati — tinggal tulis kode, klik run, dan langsung keliatan hasilnya. πŸ”₯



Contoh nya:





🧩 Struktur Kodenya

Jadi di project ini kita bikin Login & Register Page dalam satu tampilan. Caranya pake TabBar & TabBarView biar gampang switch antara tab Login ↔ Register.


import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "Login Page",
      theme: ThemeData(
        fontFamily: "Arial",
      ),
      home: const AuthPage(),
    );
  }
}

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

  @override
  State<AuthPage> createState() => _AuthPageState();
}

class _AuthPageState extends State<AuthPage> with TickerProviderStateMixin {
  late TabController _tabController;
  bool rememberMe = false;
  bool obscurePassword = true;
  bool obscureConfirmPassword = true;

  final TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);
  }

  // === Function Forgot Password ===
  void _showForgotPasswordDialog() {
    showDialog(
      context: context,
      builder: (context) {
        final TextEditingController resetEmailController =
            TextEditingController();
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
          title: const Text("Forgot Password"),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text(
                "Enter your registered email address to receive a reset link.",
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 15),
              TextField(
                controller: resetEmailController,
                decoration: InputDecoration(
                  prefixIcon: const Icon(Icons.email_outlined),
                  hintText: "example@email.com",
                  labelText: "Email Address",
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(12),
                  ),
                ),
              ),
            ],
          ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.pop(context); // Tutup dialog
              },
              child: const Text("Cancel"),
            ),
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.teal.shade300,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              onPressed: () {
                String email = resetEmailController.text.trim();
                if (email.isNotEmpty) {
                  Navigator.pop(context);
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text(
                          "Link reset password berhasil dikirim ke $email ✅"),
                    ),
                  );
                }
              },
              child: const Text("Send Reset Link"),
            ),
          ],
        );
      },
    );
  }

  // === Function Login ===
  void _login() {
    String email = emailController.text.trim();
    String password = passwordController.text.trim();

    if (email.isNotEmpty && password.isNotEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("Berhasil Login sebagai $email ✅")),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text("Email & Password wajib diisi ❌")),
      );
    }
  }

  // === Function Register ===
  void _register() {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("Akun berhasil dibuat πŸŽ‰")),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black, // background hitam
      body: SafeArea(
        child: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Icon(Icons.arrow_back, color: Colors.white, size: 28),
                const SizedBox(height: 30),

                // Judul
                const Text(
                  "Go ahead and set up\nyour account",
                  style: TextStyle(
                    fontSize: 24,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(height: 10),

                const Text(
                  "Sign in-up to enjoy the best managing experience",
                  style: TextStyle(
                    fontSize: 14,
                    color: Colors.grey,
                  ),
                ),
                const SizedBox(height: 30),

                // Card putih untuk form login/register
                Container(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(16),
                  ),
                  child: Padding(
                    padding: const EdgeInsets.all(20),
                    child: Column(
                      children: [
                        // TabBar Login & Register
                        Container(
                          decoration: BoxDecoration(
                            color: Colors.grey.shade200,
                            borderRadius: BorderRadius.circular(30),
                          ),
                          child: TabBar(
                            controller: _tabController,
                            indicator: BoxDecoration(
                              color: Colors.white,
                              borderRadius: BorderRadius.circular(30),
                            ),
                            labelColor: Colors.black,
                            unselectedLabelColor: Colors.grey,
                            tabs: const [
                              Tab(text: "Login"),
                              Tab(text: "Register"),
                            ],
                          ),
                        ),
                        const SizedBox(height: 25),

                        // TabBarView isi form Login & Register
                        SizedBox(
                          height: 500,
                          child: TabBarView(
                            controller: _tabController,
                            children: [
                              // ---------------- LOGIN ----------------
                              Column(
                                children: [
                                  TextField(
                                    controller: emailController,
                                    decoration: InputDecoration(
                                      prefixIcon: const Icon(Icons.email_outlined),
                                      hintText: "Slepet@gmail.com",
                                      labelText: "Email Address",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 20),

                                  TextField(
                                    controller: passwordController,
                                    obscureText: obscurePassword,
                                    decoration: InputDecoration(
                                      prefixIcon: const Icon(Icons.lock_outline),
                                      hintText: "Example123456789",
                                      labelText: "Password",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                      suffixIcon: IconButton(
                                        icon: Icon(
                                          obscurePassword
                                              ? Icons.visibility_off
                                              : Icons.visibility,
                                        ),
                                        onPressed: () {
                                          setState(() {
                                            obscurePassword = !obscurePassword;
                                          });
                                        },
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 15),

                                  // Remember me & Forgot password
                                  Row(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceBetween,
                                    children: [
                                      Row(
                                        children: [
                                          Checkbox(
                                            value: rememberMe,
                                            onChanged: (value) {
                                              setState(() {
                                                rememberMe = value ?? false;
                                              });
                                            },
                                          ),
                                          const Text("Remember me"),
                                        ],
                                      ),
                                      TextButton(
                                        onPressed: _showForgotPasswordDialog,
                                        child: const Text(
                                          "Forgot Password?",
                                          style: TextStyle(color: Colors.teal),
                                        ),
                                      ),
                                    ],
                                  ),
                                  const SizedBox(height: 20),

                                  // Tombol Login
                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton(
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.teal.shade300,
                                        shape: RoundedRectangleBorder(
                                          borderRadius:
                                              BorderRadius.circular(12),
                                        ),
                                        padding: const EdgeInsets.symmetric(
                                            vertical: 14),
                                      ),
                                      onPressed: _login,
                                      child: const Text(
                                        "Login",
                                        style: TextStyle(fontSize: 16),
                                      ),
                                    ),
                                  ),
                                ],
                              ),

                              // ---------------- REGISTER ----------------
                              Column(
                                children: [
                                  TextField(
                                    decoration: InputDecoration(
                                      prefixIcon: const Icon(Icons.person_outline),
                                      labelText: "Full Name",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 20),

                                  TextField(
                                    decoration: InputDecoration(
                                      prefixIcon: const Icon(Icons.email_outlined),
                                      labelText: "Email Address",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 20),

                                  TextField(
                                    obscureText: obscurePassword,
                                    decoration: InputDecoration(
                                      prefixIcon: const Icon(Icons.lock_outline),
                                      labelText: "Password",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                      suffixIcon: IconButton(
                                        icon: Icon(
                                          obscurePassword
                                              ? Icons.visibility_off
                                              : Icons.visibility,
                                        ),
                                        onPressed: () {
                                          setState(() {
                                            obscurePassword = !obscurePassword;
                                          });
                                        },
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 20),

                                  TextField(
                                    obscureText: obscureConfirmPassword,
                                    decoration: InputDecoration(
                                      prefixIcon: const Icon(Icons.lock_outline),
                                      labelText: "Confirm Password",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                      suffixIcon: IconButton(
                                        icon: Icon(
                                          obscureConfirmPassword
                                              ? Icons.visibility_off
                                              : Icons.visibility,
                                        ),
                                        onPressed: () {
                                          setState(() {
                                            obscureConfirmPassword =
                                                !obscureConfirmPassword;
                                          });
                                        },
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 25),

                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton(
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.teal.shade300,
                                        shape: RoundedRectangleBorder(
                                          borderRadius:
                                              BorderRadius.circular(12),
                                        ),
                                        padding: const EdgeInsets.symmetric(
                                            vertical: 14),
                                      ),
                                      onPressed: _register,
                                      child: const Text(
                                        "Register",
                                        style: TextStyle(fontSize: 16),
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ],
                          ),
                        )
                      ],
                    ),
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}


Kode utama ada di class AuthPage dengan beberapa widget pendukung.


⚡ Penjelasan Function & Bagian Penting

1. main() & MyLoginApp

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

πŸ‘‰ Ini basically pintu masuk aplikasi. MyLoginApp adalah widget utama yang manggil AuthPage.
Ibaratnya kayak opening gate sebelum masuk ke dunia coding lo. πŸšͺ


2. AuthPage + TabController

late TabController _tabController;

πŸ‘‰ Fungsi ini biar kita bisa pindah tab antara Login dan Register.
Bayangin aja kayak lagi geser story Instagram πŸ“², cuma bedanya ini geser form.


3. TextField Input

TextField(
  decoration: InputDecoration(
    prefixIcon: Icon(Icons.email_outlined),
    labelText: "Email Address",
  ),
)

πŸ‘‰ Ini bagian tempat user ngetik email atau password.
prefixIcon itu biar ada icon kece di sebelah kiri input — bikin vibes UI lebih modern ✨.


4. Password dengan Visibility Toggle

obscureText: obscurePassword,
suffixIcon: IconButton(
  icon: Icon(
    obscurePassword ? Icons.visibility_off : Icons.visibility,
  ),
  onPressed: () {
    setState(() {
      obscurePassword = !obscurePassword;
    });
  },
),

πŸ‘‰ Fitur ini bikin password bisa disembunyiin atau diliatin.
Kalo lagi di tempat rame, tinggal klik icon “mata” biar password lo ga diintip bocil sebelah πŸ‘€.


5. Remember Me & Forgot Password

Row(
  children: [
    Checkbox(
      value: rememberMe,
      onChanged: (value) {
        setState(() {
          rememberMe = value ?? false;
        });
      },
    ),
    Text("Remember me"),
  ],
),
TextButton(
  onPressed: _showForgotPasswordDialog,
  child: Text("Forgot Password?"),
),

πŸ‘‰ “Remember me” itu biar akun lo ke-save otomatis.
πŸ‘‰ Sedangkan tombol Forgot Password? bakal munculin popup buat reset password.
Jadi kalo lo tipe orang yang suka lupa password (kayak gue πŸ˜…), fitur ini bakal nyelametin lo.


6. Forgot Password Dialog Function

void _showForgotPasswordDialog() {
  showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: Text("Forgot Password"),
        content: TextField(...),
        actions: [
          TextButton(onPressed: () {}, child: Text("Cancel")),
          ElevatedButton(onPressed: () {}, child: Text("Send Reset Link")),
        ],
      );
    },
  );
}

πŸ‘‰ Ini fitur keren: pas lo klik Forgot Password, bakal muncul popup dialog buat masukin email.
Tinggal isi email, klik Send Reset Link, dan boom! ✉️ reset link dikirim (sementara dummy function, bisa dihubungin ke Firebase biar beneran works).


7. Login & Register Button

ElevatedButton(
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.teal.shade300,
  ),
  onPressed: () {},
  child: Text("Login"),
),

πŸ‘‰ Ini tombol utama buat action login atau register.
Bisa di-custom ke backend lo (API / Firebase). Untuk sekarang, tombolnya baru buat UI aja.


8. Login with Google & Facebook

ElevatedButton.icon(
  onPressed: () {},
  icon: Icon(Icons.g_mobiledata),
  label: Text("Google"),
),

πŸ‘‰ Fitur tambahan biar user bisa login via Google / Facebook.
Aesthetic + lebih gampang, ga perlu ribet isi form lagi. ✨


🧩 Struktur di Login Page (yang kita buat sebelumnya)

  1. Text πŸ“

    • Ada banget, contohnya buat judul “Login” dan tulisan kecil kayak “Belum punya akun?”.

    • Dipake dengan widget Text().

  2. Input (TextField) ⌨️

    • Ada 2: satu buat Email, satu buat Password.

    • Pakai TextField dengan decoration biar ada placeholder/ikon.

  3. Button πŸ–±️

    • Ada Login Button (pakai ElevatedButton).

    • Ada juga tombol kecil Forgot Password? (pakai TextButton).

    • Di halaman register kemarin juga ada tombol Register.

  4. Submit

    • Tidak ada widget bernama “submit”, tapi Login Button itu udah berfungsi sebagai tombol submit.

    • Jadi pas dipencet → jalankan function login.

  5. Card πŸ’³

    • Kalau di desain yang kita buat, form login + input dibungkus dalam Card biar keliatan rapi.

    • Jadi iya, di dalamnya ada Card().

  6. List πŸ“œ

    • Nggak ada ListView di login page (karena ini form, bukan daftar item).

    • Tapi kalau mau bikin daftar error/daftar akun, bisa pake ListView.

  7. Insert ➕

    • Di login page belum ada insert data ke database.

    • Insert biasanya ada di Register Page (ketika user nambah akun baru).




🎯 Kesimpulan

Dengan ZappRun + Flutter, lo bisa bikin login page kece, modern, dan full fitur cuma dengan beberapa baris kode.

  • Bisa login/register dalam satu halaman ✅

  • Password ada toggle mata biar aman ✅

  • Ada “Remember me” ✅

  • Forgot password dengan popup dialog ✅

  • Login via Google & Facebook ✅

Coding sekarang tuh ga harus ribet, tinggal mix n match widget + kreativitas lo.
Asik kan? πŸ’―



Mau akses?

Klik aje:


https://zshe06r0shf0.zapp.page/#/

Komentar

Postingan populer dari blog ini

MEMBUAT TAMPILAN APLIKASI SEDERANA MENGGUNAKAN DART FLUTTER

Aplication Flutter With Image 7/31/2025