AMP Analytics -->

Teknoloji Rehberi

12 Haziran 2025 Perşembe

Gelişmiş Not Defteri Uygulaması (Kotlin-Android)

 

Gelişmiş Not Defteri Uygulaması - Kotlin (Android)

Aşağıda, Android için Kotlin dilinde gelişmiş bir not defteri uygulamasının temel yapısını içeren bir örnek bulunmaktadır. Bu örnekte XML layout dosyası ve temel Kotlin kodu yer almaktadır.

1. activity_main.xml (Ana Layout)

xml
Copy
Download
Run
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/Theme.NotDefteri.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/Theme.NotDefteri.PopupOverlay"
            app:title="@string/app_name" />

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab_add_note"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@drawable/ic_add" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

2. content_main.xml (İçerik Layout)

xml
Copy
Download
Run
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/activity_main">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_notes"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:padding="8dp"
        app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
        app:spanCount="2"
        tools:listitem="@layout/item_note" />

    <TextView
        android:id="@+id/text_empty_notes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/no_notes_found"
        android:textSize="18sp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

3. item_note.xml (Not Öğesi Layout)

xml
Copy
Download
Run
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="4dp"
    app:cardCornerRadius="8dp"
    app:cardElevation="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:id="@+id/text_note_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/text_note_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:maxLines="3"
            android:textColor="@android:color/darker_gray" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/text_note_date"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:textColor="@android:color/darker_gray"
                android:textSize="12sp" />

            <ImageView
                android:id="@+id/image_note_pin"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_gravity="end"
                android:src="@drawable/ic_pin"
                android:visibility="gone" />

        </LinearLayout>

    </LinearLayout>

</androidx.cardview.widget.CardView>

4. activity_note_detail.xml (Not Detay Sayfası)

xml
Copy
Download
Run
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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"
    tools:context=".NoteDetailActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/Theme.NotDefteri.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/Theme.NotDefteri.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">

            <EditText
                android:id="@+id/edit_note_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/title"
                android:textSize="24sp"
                android:textStyle="bold" />

            <EditText
                android:id="@+id/edit_note_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:gravity="top"
                android:hint="@string/content"
                android:inputType="textMultiLine"
                android:minHeight="200dp" />

        </LinearLayout>

    </ScrollView>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab_save_note"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@drawable/ic_save" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

5. MainActivity.kt (Ana Aktivite)

kotlin
Copy
Download
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var fabAddNote: FloatingActionButton
    private lateinit var adapter: NotesAdapter
    private lateinit var noteDatabase: NoteDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(findViewById(R.id.toolbar))

        // Initialize views
        recyclerView = findViewById(R.id.recycler_notes)
        fabAddNote = findViewById(R.id.fab_add_note)

        // Initialize database
        noteDatabase = NoteDatabase.getInstance(this)

        // Setup RecyclerView
        adapter = NotesAdapter { note ->
            openNoteDetail(note.id)
        }
        recyclerView.adapter = adapter

        // Load notes
        loadNotes()

        // Set click listeners
        fabAddNote.setOnClickListener {
            openNoteDetail(null)
        }
    }

    private fun loadNotes() {
        val notes = noteDatabase.noteDao().getAllNotes()
        adapter.submitList(notes)
        findViewById<TextView>(R.id.text_empty_notes).visibility = 
            if (notes.isEmpty()) View.VISIBLE else View.GONE
    }

    private fun openNoteDetail(noteId: Long?) {
        val intent = Intent(this, NoteDetailActivity::class.java)
        if (noteId != null) {
            intent.putExtra(NoteDetailActivity.EXTRA_NOTE_ID, noteId)
        }
        startActivity(intent)
    }

    override fun onResume() {
        super.onResume()
        loadNotes()
    }
}

6. NoteDetailActivity.kt (Not Detay Aktivitesi)

kotlin
Copy
Download
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

class NoteDetailActivity : AppCompatActivity() {

    companion object {
        const val EXTRA_NOTE_ID = "extra_note_id"
    }

    private lateinit var editTitle: EditText
    private lateinit var editContent: EditText
    private lateinit var fabSave: FloatingActionButton
    private lateinit var noteDatabase: NoteDatabase

    private var noteId: Long? = null
    private var currentNote: Note? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_note_detail)
        setSupportActionBar(findViewById(R.id.toolbar))
        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        // Initialize views
        editTitle = findViewById(R.id.edit_note_title)
        editContent = findViewById(R.id.edit_note_content)
        fabSave = findViewById(R.id.fab_save_note)

        // Initialize database
        noteDatabase = NoteDatabase.getInstance(this)

        // Get note ID from intent
        noteId = intent.getLongExtra(EXTRA_NOTE_ID, -1).takeIf { it != -1L }

        // Load note if editing
        if (noteId != null) {
            loadNote()
        }

        // Set click listeners
        fabSave.setOnClickListener {
            saveNote()
        }
    }

    private fun loadNote() {
        lifecycleScope.launch {
            currentNote = noteDatabase.noteDao().getNoteById(noteId!!)
            currentNote?.let {
                editTitle.setText(it.title)
                editContent.setText(it.content)
            }
        }
    }

    private fun saveNote() {
        val title = editTitle.text.toString().trim()
        val content = editContent.text.toString().trim()

        if (title.isEmpty()) {
            editTitle.error = "Başlık boş olamaz"
            return
        }

        val note = currentNote?.copy(
            title = title,
            content = content,
            updatedAt = System.currentTimeMillis()
        ) ?: Note(
            title = title,
            content = content,
            createdAt = System.currentTimeMillis(),
            updatedAt = System.currentTimeMillis()
        )

        lifecycleScope.launch {
            if (noteId != null) {
                noteDatabase.noteDao().updateNote(note)
            } else {
                noteDatabase.noteDao().insertNote(note)
            }
            finish()
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        onBackPressed()
        return true
    }
}

7. NotesAdapter.kt (RecyclerView Adapter)

kotlin
Copy
Download
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView

class NotesAdapter(private val onNoteClicked: (Note) -> Unit) :
    ListAdapter<Note, NotesAdapter.NoteViewHolder>(NoteDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_note, parent, false)
        return NoteViewHolder(view)
    }

    override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
        val note = getItem(position)
        holder.bind(note)
        holder.itemView.setOnClickListener { onNoteClicked(note) }
    }

    class NoteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val titleView: TextView = itemView.findViewById(R.id.text_note_title)
        private val contentView: TextView = itemView.findViewById(R.id.text_note_content)
        private val dateView: TextView = itemView.findViewById(R.id.text_note_date)
        private val pinView: ImageView = itemView.findViewById(R.id.image_note_pin)

        fun bind(note: Note) {
            titleView.text = note.title
            contentView.text = note.content
            
            val dateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault())
            dateView.text = dateFormat.format(Date(note.updatedAt))
            
            pinView.visibility = if (note.isPinned) View.VISIBLE else View.GONE
        }
    }
}

class NoteDiffCallback : DiffUtil.ItemCallback<Note>() {
    override fun areItemsTheSame(oldItem: Note, newItem: Note): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: Note, newItem: Note): Boolean {
        return oldItem == newItem
    }
}

8. Note.kt (Veri Modeli)

kotlin
Copy
Download
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Long = 0,
    val title: String,
    val content: String,
    val createdAt: Long,
    val updatedAt: Long,
    val isPinned: Boolean = false,
    val color: Int = 0
)

9. NoteDatabase.kt (Room Database)

kotlin
Copy
Download
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context

@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {

    abstract fun noteDao(): NoteDao

    companion object {
        @Volatile
        private var INSTANCE: NoteDatabase? = null

        fun getInstance(context: Context): NoteDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    NoteDatabase::class.java,
                    "note_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

10. NoteDao.kt (Room DAO)

kotlin
Copy
Download
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow

@Dao
interface NoteDao {

    @Insert
    suspend fun insertNote(note: Note): Long

    @Update
    suspend fun updateNote(note: Note)

    @Query("SELECT * FROM notes ORDER BY isPinned DESC, updatedAt DESC")
    fun getAllNotes(): List<Note>

    @Query("SELECT * FROM notes WHERE id = :noteId")
    suspend fun getNoteById(noteId: Long): Note?

    @Query("DELETE FROM notes WHERE id = :noteId")
    suspend fun deleteNote(noteId: Long)
}

Bu örnek, temel bir not defteri uygulamasının tüm ana bileşenlerini içermektedir. Uygulamayı daha da geliştirmek için aşağıdaki özellikleri ekleyebilirsiniz:

  1. Notları renklendirme özelliği

  2. Kategorilere göre filtreleme

  3. Arama fonksiyonu

  4. Notları sabitleme (pin) özelliği

  5. Geri dönüşüm kutusu ve geri yükleme

  6. Bulut senkronizasyonu

  7. Biçimlendirme seçenekleri (kalın, italik, vs.)

  8. Resim ekleme desteği

Uygulamayı çalıştırabilmek için build.gradle dosyanıza Room, Coroutines ve Material Design bağımlılıklarını eklemeyi unutmayın.

Hiç yorum yok:

Yorum Gönder

Popular Posts