Kotlin ile Email Girişli Uygulama Örneği

 

Kotlin ile Email Girişli Uygulama Örneği

Aşağıda Kotlin'de (Android için) email ile giriş yapılan bir uygulamanın temel yapısını ve arayüzünü gösteren bir örnek bulabilirsiniz.

1. XML Arayüz Dosyası (activity_login.xml)

xml
Copy
Download
Run
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="24dp"
    tools:context=".LoginActivity">

    <ImageView
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="32dp"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="24dp"
        android:text="Hoş Geldiniz"
        android:textSize="24sp"
        android:textStyle="bold" />

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/etEmail"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Email"
            android:inputType="textEmailAddress" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/etPassword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Şifre"
            android:inputType="textPassword" />
    </com.google.android.material.textfield.TextInputLayout>

    <Button
        android:id="@+id/btnLogin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="Giriş Yap" />

    <TextView
        android:id="@+id/tvForgotPassword"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Şifremi Unuttum"
        android:textColor="@color/purple_500" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginVertical="24dp"
        android:background="#E0E0E0" />

    <Button
        android:id="@+id/btnRegister"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hesap Oluştur"
        android:backgroundTint="@color/gray"
        android:textColor="@color/white" />

</LinearLayout>

2. Kotlin Activity (LoginActivity.kt)

kotlin
Copy
Download
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.textfield.TextInputEditText
import com.google.firebase.auth.FirebaseAuth

class LoginActivity : AppCompatActivity() {

    private lateinit var auth: FirebaseAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        // Firebase Auth başlatma
        auth = FirebaseAuth.getInstance()

        val etEmail = findViewById<TextInputEditText>(R.id.etEmail)
        val etPassword = findViewById<TextInputEditText>(R.id.etPassword)
        val btnLogin = findViewById<Button>(R.id.btnLogin)
        val tvForgotPassword = findViewById<TextView>(R.id.tvForgotPassword)
        val btnRegister = findViewById<Button>(R.id.btnRegister)

        btnLogin.setOnClickListener {
            val email = etEmail.text.toString().trim()
            val password = etPassword.text.toString().trim()

            if (email.isEmpty() || password.isEmpty()) {
                Toast.makeText(this, "Email ve şifre giriniz", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            loginUser(email, password)
        }

        tvForgotPassword.setOnClickListener {
            // Şifremi unuttum ekranına yönlendir
            startActivity(Intent(this, ForgotPasswordActivity::class.java))
        }

        btnRegister.setOnClickListener {
            // Kayıt ekranına yönlendir
            startActivity(Intent(this, RegisterActivity::class.java))
        }
    }

    private fun loginUser(email: String, password: String) {
        auth.signInWithEmailAndPassword(email, password)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Giriş başarılı, ana ekrana yönlendir
                    val intent = Intent(this, MainActivity::class.java)
                    startActivity(intent)
                    finish()
                } else {
                    // Giriş başarısız
                    Toast.makeText(
                        this, 
                        "Giriş başarısız: ${task.exception?.message}",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
    }

    override fun onStart() {
        super.onStart()
        // Kullanıcı zaten giriş yapmışsa ana ekrana yönlendir
        if (auth.currentUser != null) {
            startActivity(Intent(this, MainActivity::class.java))
            finish()
        }
    }
}

3. Firebase Bağımlılıkları (build.gradle)

gradle
Copy
Download
implementation 'com.google.firebase:firebase-auth-ktx:22.3.1'
implementation 'com.google.android.material:material:1.11.0'

4. Ekran Görüntüsü

Bu tasarım şu öğeleri içerir:

  • Uygulama logosu

  • "Hoş Geldiniz" başlığı

  • Email giriş alanı

  • Şifre giriş alanı

  • Giriş yap butonu

  • Şifremi unuttum bağlantısı

  • Hesap oluştur butonu

Hesap Oluşturma Aktivitesi (SignUpActivity)

İşte genişletilmiş bir Hesap Oluşturma aktivitesi örneği:

1. XML Arayüzü (activity_sign_up.xml)

xml
Copy
Download
Run
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="24dp"
        tools:context=".SignUpActivity">

        <ImageView
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="32dp"
            android:src="@drawable/ic_account_circle" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="24dp"
            android:text="Hesap Oluştur"
            android:textColor="@color/primaryColor"
            android:textSize="28sp"
            android:textStyle="bold" />

        <!-- Ad Soyad -->
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            app:errorEnabled="true">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/etFullName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Ad Soyad"
                android:inputType="textPersonName"
                android:maxLines="1" />
        </com.google.android.material.textfield.TextInputLayout>

        <!-- Email -->
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            app:errorEnabled="true">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/etEmail"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Email"
                android:inputType="textEmailAddress"
                android:maxLines="1" />
        </com.google.android.material.textfield.TextInputLayout>

        <!-- Şifre -->
        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/tilPassword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            app:errorEnabled="true"
            app:passwordToggleEnabled="true">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/etPassword"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Şifre"
                android:inputType="textPassword"
                android:maxLines="1" />
        </com.google.android.material.textfield.TextInputLayout>

        <!-- Şifre Tekrar -->
        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            app:errorEnabled="true"
            app:passwordToggleEnabled="true">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/etConfirmPassword"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Şifre Tekrar"
                android:inputType="textPassword"
                android:maxLines="1" />
        </com.google.android.material.textfield.TextInputLayout>

        <!-- Kullanım Koşulları -->
        <CheckBox
            android:id="@+id/cbTerms"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:text="Kullanım koşullarını kabul ediyorum" />

        <!-- Kayıt Butonu -->
        <Button
            android:id="@+id/btnSignUp"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_marginBottom="16dp"
            android:backgroundTint="@color/primaryColor"
            android:text="Kayıt Ol"
            android:textColor="@android:color/white" />

        <!-- Giriş Yap Linki -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Zaten hesabınız var mı? Giriş Yap"
            android:textColor="@color/primaryColor">

            <androidx.appcompat.widget.AppCompatTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColorLink="@color/primaryColor"
                android:text="Zaten hesabınız var mı? Giriş Yap" />
        </TextView>

    </LinearLayout>
</ScrollView>

2. Kotlin Kodu (SignUpActivity.kt)

kotlin
Copy
Download
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Patterns
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.textfield.TextInputLayout
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.UserProfileChangeRequest
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.android.synthetic.main.activity_sign_up.*

class SignUpActivity : AppCompatActivity() {

    private lateinit var auth: FirebaseAuth
    private lateinit var db: FirebaseFirestore

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign_up)

        // Firebase başlat
        auth = FirebaseAuth.getInstance()
        db = FirebaseFirestore.getInstance()

        // Input validasyonları
        setupFormValidation()

        btnSignUp.setOnClickListener {
            attemptSignUp()
        }

        // Giriş yap linki
        findViewById<TextView>(R.id.textView).setOnClickListener {
            startActivity(Intent(this, LoginActivity::class.java))
            finish()
        }
    }

    private fun setupFormValidation() {
        // Ad soyad validasyonu
        etFullName.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                validateName()
            }
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        })

        // Email validasyonu
        etEmail.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                validateEmail()
            }
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        })

        // Şifre validasyonu
        etPassword.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                validatePassword()
                validateConfirmPassword()
            }
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        })

        // Şifre tekrar validasyonu
        etConfirmPassword.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                validateConfirmPassword()
            }
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        })
    }

    private fun validateName(): Boolean {
        return if (etFullName.text.toString().trim().isEmpty()) {
            (etFullName.parent.parent as TextInputLayout).error = "Ad soyad giriniz"
            false
        } else {
            (etFullName.parent.parent as TextInputLayout).error = null
            true
        }
    }

    private fun validateEmail(): Boolean {
        val email = etEmail.text.toString().trim()
        return when {
            email.isEmpty() -> {
                (etEmail.parent.parent as TextInputLayout).error = "Email giriniz"
                false
            }
            !Patterns.EMAIL_ADDRESS.matcher(email).matches() -> {
                (etEmail.parent.parent as TextInputLayout).error = "Geçerli bir email giriniz"
                false
            }
            else -> {
                (etEmail.parent.parent as TextInputLayout).error = null
                true
            }
        }
    }

    private fun validatePassword(): Boolean {
        val password = etPassword.text.toString()
        return when {
            password.isEmpty() -> {
                tilPassword.error = "Şifre giriniz"
                false
            }
            password.length < 6 -> {
                tilPassword.error = "Şifre en az 6 karakter olmalı"
                false
            }
            else -> {
                tilPassword.error = null
                true
            }
        }
    }

    private fun validateConfirmPassword(): Boolean {
        val password = etPassword.text.toString()
        val confirmPassword = etConfirmPassword.text.toString()
        return when {
            confirmPassword.isEmpty() -> {
                (etConfirmPassword.parent.parent as TextInputLayout).error = "Şifre tekrar giriniz"
                false
            }
            confirmPassword != password -> {
                (etConfirmPassword.parent.parent as TextInputLayout).error = "Şifreler uyuşmuyor"
                false
            }
            else -> {
                (etConfirmPassword.parent.parent as TextInputLayout).error = null
                true
            }
        }
    }

    private fun validateTerms(): Boolean {
        return if (!cbTerms.isChecked) {
            Toast.makeText(this, "Kullanım koşullarını kabul etmelisiniz", Toast.LENGTH_SHORT).show()
            false
        } else {
            true
        }
    }

    private fun attemptSignUp() {
        if (!validateName() || !validateEmail() || !validatePassword() || 
            !validateConfirmPassword() || !validateTerms()) {
            return
        }

        val name = etFullName.text.toString().trim()
        val email = etEmail.text.toString().trim()
        val password = etPassword.text.toString()

        btnSignUp.isEnabled = false
        btnSignUp.text = "Hesap oluşturuluyor..."

        auth.createUserWithEmailAndPassword(email, password)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Kullanıcı adını güncelle
                    val user = auth.currentUser
                    val profileUpdates = UserProfileChangeRequest.Builder()
                        .setDisplayName(name)
                        .build()

                    user?.updateProfile(profileUpdates)
                        ?.addOnCompleteListener { profileTask ->
                            if (profileTask.isSuccessful) {
                                // Firestore'a ek bilgileri kaydet
                                saveAdditionalUserData(user.uid, name, email)
                            } else {
                                btnSignUp.isEnabled = true
                                btnSignUp.text = "Kayıt Ol"
                                Toast.makeText(
                                    this,
                                    "Profil güncelleme hatası: ${profileTask.exception?.message}",
                                    Toast.LENGTH_SHORT
                                ).show()
                            }
                        }
                } else {
                    btnSignUp.isEnabled = true
                    btnSignUp.text = "Kayıt Ol"
                    Toast.makeText(
                        this,
                        "Kayıt başarısız: ${task.exception?.message}",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
    }

    private fun saveAdditionalUserData(userId: String, name: String, email: String) {
        val user = hashMapOf(
            "name" to name,
            "email" to email,
            "createdAt" to System.currentTimeMillis()
        )

        db.collection("users").document(userId)
            .set(user)
            .addOnSuccessListener {
                Toast.makeText(this, "Kayıt başarılı!", Toast.LENGTH_SHORT).show()
                startActivity(Intent(this, MainActivity::class.java))
                finishAffinity()
            }
            .addOnFailureListener { e ->
                btnSignUp.isEnabled = true
                btnSignUp.text = "Kayıt Ol"
                Toast.makeText(
                    this,
                    "Veri kaydetme hatası: ${e.message}",
                    Toast.LENGTH_SHORT
                ).show()
            }
    }
}

3. Özellikler

  1. Kapsamlı Form Validasyonu:

    • Gerçek zamanlı input validasyonu

    • Email format kontrolü

    • Şifre eşleşme kontrolü

    • Minimum şifre uzunluğu kontrolü (6 karakter)

    • Zorunlu alan kontrolü

  2. Kullanıcı Deneyimi:

    • ScrollView ile uzun form desteği

    • Şifre göster/gizle butonu

    • Buton durum yönetimi (yükleme durumunda devre dışı bırakma)

    • Kullanıcı dostu hata mesajları

  3. Firebase Entegrasyonu:

    • Email/şifre ile kullanıcı kaydı

    • Kullanıcı profil bilgilerini güncelleme

    • Firestore'a ek kullanıcı verilerini kaydetme

  4. Güvenlik:

    • Kullanım koşulları onayı zorunluluğu

    • Firebase Authentication güvenlik kuralları

  5. Geçişler:

    • Giriş ekranına kolay dönüş

    • Başarılı kayıt sonrası ana ekrana yönlendirme

Kotlin Kodu (RegisterActivity.kt)

kotlin
Copy
Download
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.textfield.TextInputEditText
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.UserProfileChangeRequest

class RegisterActivity : AppCompatActivity() {

    private lateinit var auth: FirebaseAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_register)

        auth = FirebaseAuth.getInstance()

        val etName = findViewById<TextInputEditText>(R.id.etName)
        val etEmail = findViewById<TextInputEditText>(R.id.etEmail)
        val etPassword = findViewById<TextInputEditText>(R.id.etPassword)
        val etConfirmPassword = findViewById<TextInputEditText>(R.id.etConfirmPassword)
        val btnRegister = findViewById<Button>(R.id.btnRegister)
        val tvLogin = findViewById<TextView>(R.id.tvLogin)

        btnRegister.setOnClickListener {
            val name = etName.text.toString().trim()
            val email = etEmail.text.toString().trim()
            val password = etPassword.text.toString().trim()
            val confirmPassword = etConfirmPassword.text.toString().trim()

            if (name.isEmpty() || email.isEmpty() || password.isEmpty()) {
                Toast.makeText(this, "Tüm alanları doldurunuz", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            if (password != confirmPassword) {
                Toast.makeText(this, "Şifreler uyuşmuyor", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            if (password.length < 6) {
                Toast.makeText(this, "Şifre en az 6 karakter olmalı", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            registerUser(name, email, password)
        }

        tvLogin.setOnClickListener {
            startActivity(Intent(this, LoginActivity::class.java))
            finish()
        }
    }

    private fun registerUser(name: String, email: String, password: String) {
        auth.createUserWithEmailAndPassword(email, password)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Kullanıcı adını güncelle
                    val user = auth.currentUser
                    val profileUpdates = UserProfileChangeRequest.Builder()
                        .setDisplayName(name)
                        .build()

                    user?.updateProfile(profileUpdates)
                        ?.addOnCompleteListener { profileTask ->
                            if (profileTask.isSuccessful) {
                                // Kayıt başarılı, giriş ekranına yönlendir
                                Toast.makeText(
                                    this,
                                    "Kayıt başarılı. Giriş yapabilirsiniz.",
                                    Toast.LENGTH_SHORT
                                ).show()
                                startActivity(Intent(this, LoginActivity::class.java))
                                finish()
                            }
                        }
                } else {
                    Toast.makeText(
                        this,
                        "Kayıt başarısız: ${task.exception?.message}",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
    }
}

Özellikler


  1. Email Doğrulama: Email alanı otomatik olarak email formatını kontrol eder.

  2. Şifre Gizleme: Şifre alanı girilen karakterleri gizler.

  3. Firebase Entegrasyonu: Firebase Authentication ile email/şifre doğrulaması yapar.

  4. Oturum Kontrolü: Kullanıcı zaten giriş yapmışsa direkt ana ekrana yönlendirir.

  5. Hata Yönetimi: Giriş hatalarını kullanıcıya gösterir.


ForgotPasswordActivity:

  • Email doğrulama

  • Firebase şifre sıfırlama emaili gönderme

  • Kullanıcı dostu geri bildirim mesajları

  • Giriş ekranına kolay dönüş

RegisterActivity:

  • Ad, email, şifre ve şifre tekrar alanları

  • Şifre doğrulama (eşleşme kontrolü)

  • Minimum şifre uzunluğu kontrolü

  • Firebase kullanıcı kaydı

  • Kullanıcı adı (display name) güncelleme

  • Başarılı kayıt sonrası giriş ekranına yönlendirme


Yorum Gönder

0 Yorumlar