Forráskód Böngészése

Note ctreation, editing, deletion refined

sduduzog 7 éve
szülő
commit
1cdf14e45c

+ 0 - 1
app/build.gradle

@@ -57,7 +57,6 @@ dependencies {
 
     // 3rd Party libs
     implementation 'com.daasuu:EasingInterpolator:1.0.0'
-    // implementation 'com.getbase:floatingactionbutton:1.10.1'
 
     // Test libs
     testImplementation 'junit:junit:4.12'

+ 13 - 0
app/src/main/java/com/sduduzog/slimlauncher/data/DataRepository.kt

@@ -50,6 +50,10 @@ class DataRepository(application: Application) {
         SaveNoteAsyncTask(noteDao).execute(note)
     }
 
+    fun updateNote(note: Note){
+        UpdateNoteAsyncTask(noteDao).execute(note)
+    }
+
     fun deleteNote(note: Note){
         DeleteNoteAsyncTask(noteDao).execute(note)
     }
@@ -108,6 +112,15 @@ class DataRepository(application: Application) {
         }
     }
 
+    private class UpdateNoteAsyncTask internal constructor(private val mAsyncTaskDao: NoteDao) : AsyncTask<Note, Void, Void>() {
+
+        override fun doInBackground(vararg params: Note): Void? {
+            val note = params[0]
+            mAsyncTaskDao.updateNote(note)
+            return null
+        }
+    }
+
     private class DeleteNoteAsyncTask internal constructor(private val mAsyncTaskDao: NoteDao) : AsyncTask<Note, Void, Void>() {
 
         override fun doInBackground(vararg params: Note): Void? {

+ 4 - 1
app/src/main/java/com/sduduzog/slimlauncher/data/NoteDao.kt

@@ -6,12 +6,15 @@ import androidx.room.*
 @Dao
 interface NoteDao {
 
-    @get:Query("SELECT * FROM notes ORDER BY id ASC")
+    @get:Query("SELECT * FROM notes ORDER BY id DESC")
     val notes: LiveData<List<Note>>
 
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     fun saveNote(note: Note)
 
+    @Update
+    fun updateNote(note: Note)
+
     @Delete
     fun deleteNote(note: Note)
 }

+ 25 - 0
app/src/main/java/com/sduduzog/slimlauncher/ui/main/DoubleClickListener.kt

@@ -0,0 +1,25 @@
+package com.sduduzog.slimlauncher.ui.main
+
+import android.view.View
+
+abstract class DoubleClickListener: View.OnClickListener { // courtesy of Xar E Ahmer @ stackoverflow
+
+    private var lastTickTime: Long = 0
+
+    override fun onClick(view: View) {
+        val clickTime = System.currentTimeMillis()
+        if (clickTime - lastTickTime < DOUBLE_CLICK_TIME_DELTA){
+            onDoubleClick(view)
+        } else {
+            onSingleClick(view)
+        }
+        lastTickTime = clickTime
+    }
+
+    abstract fun onDoubleClick(v: View)
+    abstract fun onSingleClick(v: View)
+
+    companion object {
+        const val DOUBLE_CLICK_TIME_DELTA = 300 // milliseconds
+    }
+}

+ 2 - 0
app/src/main/java/com/sduduzog/slimlauncher/ui/main/MainFragment.kt

@@ -81,6 +81,8 @@ class MainFragment : Fragment() {
             }
         }
 
+        buttonNotes.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_mainFragment_to_notesListFragment))
+
         buttonDialer.setOnClickListener {
             try {
                 val intent = Intent(Intent.ACTION_DIAL)

+ 59 - 14
app/src/main/java/com/sduduzog/slimlauncher/ui/main/notes/NoteFragment.kt

@@ -12,7 +12,10 @@ import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProviders
 import com.sduduzog.slimlauncher.R
 import com.sduduzog.slimlauncher.data.Note
+import com.sduduzog.slimlauncher.ui.main.DoubleClickListener
 import kotlinx.android.synthetic.main.note_fragment.*
+import java.security.MessageDigest
+import java.util.*
 
 
 class NoteFragment : Fragment() {
@@ -22,6 +25,7 @@ class NoteFragment : Fragment() {
 
     private lateinit var note: Note
     private lateinit var viewModel: NotesViewModel
+    private lateinit var initialDigest: String
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -32,7 +36,7 @@ class NoteFragment : Fragment() {
                 Note("", -1L)
             }
         }
-        Log.d(TAG, "$note")
+        initialDigest = hash(note.title + note.body)
         viewModel = ViewModelProviders.of(this).get(NotesViewModel::class.java)
     }
 
@@ -45,27 +49,68 @@ class NoteFragment : Fragment() {
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
         if (note.edited == -1L) {
-            if (bodyEditText.requestFocus()) {
-                val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
-                imm.showSoftInput(bodyEditText, InputMethodManager.SHOW_IMPLICIT)
-            }
+            editBody()
+        } else {
+            bodyEditText.visibility = View.INVISIBLE
+            textBody.visibility = View.VISIBLE
+            textBody.text = note.body
+            titleEditText.setText(note.title.orEmpty())
+            bodyEditText.setText(note.body)
+            titleEditText.isEnabled = false
+        }
+        titleEditText.setOnClickListener {
+            Log.d(TAG, "title edit")
         }
+        titleEditText.setOnEditorActionListener { _, _, _ ->
+            editBody()
+            true
+        }
+        note_fragment.setOnClickListener(object : DoubleClickListener() {
+            override fun onDoubleClick(v: View) {
+                titleEditText.isEnabled = true
+                editBody()
+            }
+
+            override fun onSingleClick(v: View) {
+
+            }
+        })
     }
 
-    override fun onStop() {
-        super.onStop()
+    override fun onPause() {
+        super.onPause()
         saveNote()
     }
 
+    private fun editBody() {
+        textBody.visibility = View.INVISIBLE
+        bodyEditText.visibility = View.VISIBLE
+        txtDoubleTap.visibility = View.INVISIBLE
+        if (bodyEditText.requestFocus()) {
+            val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+            imm.showSoftInput(bodyEditText, InputMethodManager.SHOW_IMPLICIT)
+            bodyEditText.setSelection(note.body.length)
+        }
+    }
+
     private fun saveNote() {
         val body = bodyEditText.text.toString()
         val title = titleEditText.text.toString()
-        if (title.isNotEmpty()){
-            note.title = title
-        }
-        if (body.isNotEmpty()) {
-            note.body = body
-            viewModel.saveNote(note)
-        }
+        val newNote = Note(body, Date().time)
+        newNote.title = if (title.isEmpty()) null else title
+        newNote.body = body
+        newNote.id = note.id
+        val currentDigest = hash(newNote.title + newNote.body)
+        if (body.isEmpty()) return
+        if (initialDigest == currentDigest) return
+        if (note.id == null) viewModel.saveNote(newNote) else viewModel.updateNote(newNote)
+
+    }
+
+    private fun hash(input: String): String {
+        val bytes = input.toByteArray(charset("UTF-8"))
+        val md = MessageDigest.getInstance("MD5")
+        md.update(bytes)
+        return String(md.digest())
     }
 }

+ 6 - 5
app/src/main/java/com/sduduzog/slimlauncher/ui/main/notes/NotesListAdapter.kt

@@ -1,5 +1,6 @@
 package com.sduduzog.slimlauncher.ui.main.notes
 
+import android.graphics.Color
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -38,7 +39,7 @@ class NotesListAdapter(private val fragment: NotesListFragment) : RecyclerView.A
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
         val note = notes[position]
         with(note.title) {
-            if (this != null) {
+            if (this != null && this.isNotEmpty()) {
                 holder.title.text = this
                 holder.title.visibility = View.VISIBLE
             } else {
@@ -46,8 +47,8 @@ class NotesListAdapter(private val fragment: NotesListFragment) : RecyclerView.A
             }
         }
         holder.body.text = note.body
-        val fWatchDate = SimpleDateFormat("MMM dd, hh:mm", Locale.ENGLISH)
-        holder.edited.text = fWatchDate.format(note.edited)
+        val fWatchDate = SimpleDateFormat("HH:mm, MMMM dd, yyyy", Locale.US)
+        holder.edited.text = fragment.getString(R.string.notes_date_placeholder, fWatchDate.format(note.edited))
         val bundle = Bundle()
         bundle.putSerializable("note", note)
         holder.itemView.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_openNoteFragment, bundle))
@@ -66,6 +67,7 @@ class NotesListAdapter(private val fragment: NotesListFragment) : RecyclerView.A
             val note = notes[position]
             viewModel.deleteNote(note)
             Snackbar.make(fragment.view!!, "Note deleted successfully", Snackbar.LENGTH_LONG)
+                    .setActionTextColor(Color.WHITE)
                     .setAction("UNDO") {
                         viewModel.saveNote(note)
                     }
@@ -84,8 +86,7 @@ class NotesListAdapter(private val fragment: NotesListFragment) : RecyclerView.A
         notes.addAll(newList)
         if (size > newList.size) {
             notifyItemRemoved(deletedFrom)
-        } else if (size < newList.size) notifyDataSetChanged()
-
+        } else notifyDataSetChanged()
     }
 
     inner class ViewHolder(mView: View) : RecyclerView.ViewHolder(mView) {

+ 14 - 1
app/src/main/java/com/sduduzog/slimlauncher/ui/main/notes/NotesListFragment.kt

@@ -1,6 +1,8 @@
 package com.sduduzog.slimlauncher.ui.main.notes
 
 
+import android.animation.ObjectAnimator
+import android.animation.PropertyValuesHolder
 import android.os.Bundle
 import android.util.Log
 import android.view.LayoutInflater
@@ -10,10 +12,11 @@ import androidx.fragment.app.Fragment
 import androidx.navigation.Navigation
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.RecyclerView
+import com.daasuu.ei.Ease
+import com.daasuu.ei.EasingInterpolator
 import com.sduduzog.slimlauncher.R
 import com.sduduzog.slimlauncher.ui.main.OnItemActionListener
 import kotlinx.android.synthetic.main.notes_list_fragment.*
-import kotlinx.android.synthetic.main.settings_fragment.*
 
 
 class NotesListFragment : Fragment() {
@@ -58,5 +61,15 @@ class NotesListFragment : Fragment() {
         val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback)
 
         itemTouchHelper.attachToRecyclerView(notesList)
+        showFabAnimation(fab_add_note)
+    }
+
+    private fun showFabAnimation(targetView: View) {
+        val scaleX = PropertyValuesHolder.ofFloat("scaleX", 0f, 1f)
+        val scaleY = PropertyValuesHolder.ofFloat("scaleY", 0f, 1f)
+        val animator = ObjectAnimator.ofPropertyValuesHolder(targetView, scaleX, scaleY)
+        animator.interpolator = EasingInterpolator(Ease.SINE_IN_OUT)
+        animator.duration = 100
+        animator.start()
     }
 }

+ 4 - 0
app/src/main/java/com/sduduzog/slimlauncher/ui/main/notes/NotesViewModel.kt

@@ -22,6 +22,10 @@ class NotesViewModel(application: Application) : AndroidViewModel(application) {
         _repository.saveNote(note)
     }
 
+    fun updateNote(note: Note){
+        _repository.updateNote(note)
+    }
+
     fun deleteNote(note: Note){
         _repository.deleteNote(note)
     }

+ 15 - 0
app/src/main/res/anim/slide_down_enter.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="@android:anim/accelerate_decelerate_interpolator">
+
+    <translate
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromYDelta="-100%p"
+        android:toYDelta="0%p" />
+
+    <alpha
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromAlpha="0.5"
+        android:toAlpha="1.0" />
+
+</set>

+ 13 - 0
app/src/main/res/anim/slide_down_exit.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="@android:anim/accelerate_decelerate_interpolator">
+    <translate
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromYDelta="0%p"
+        android:toYDelta="100%p" />
+
+    <alpha
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromAlpha="1.0"
+        android:toAlpha="0.0" />
+</set>

+ 12 - 0
app/src/main/res/anim/slide_up_enter.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="@android:anim/accelerate_decelerate_interpolator">
+    <translate
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromYDelta="100%p"
+        android:toYDelta="0%p" />
+    <alpha
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromAlpha="0.5"
+        android:toAlpha="1.0" />
+</set>

+ 13 - 0
app/src/main/res/anim/slide_up_exit.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="@android:anim/accelerate_decelerate_interpolator">
+    <translate
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromYDelta="0%p"
+        android:toYDelta="-100%p" />
+
+    <alpha
+        android:duration="@android:integer/config_shortAnimTime"
+        android:fromAlpha="1.0"
+        android:toAlpha="0.0" />
+</set>

+ 33 - 20
app/src/main/res/layout/main_fragment.xml

@@ -30,9 +30,8 @@
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/mainAppsList"
         android:layout_width="0dp"
-        android:layout_height="wrap_content"
+        android:layout_height="320dp"
         android:layout_marginStart="16dp"
-        android:layout_marginTop="32dp"
         android:layout_marginEnd="16dp"
         app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -50,40 +49,54 @@
         app:layout_constraintStart_toEndOf="@+id/clockTextView"
         app:layout_constraintTop_toTopOf="@+id/clockTextView" />
 
-    <Button
-        android:id="@+id/buttonDialer"
-        style="@style/Widget.AppCompat.Button.Borderless"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="8dp"
-        android:text="@string/main_button_dialer"
-        android:textAppearance="@style/TextAppearance.AppCompat"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
-
     <ImageView
         android:id="@+id/ivExpand"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
         android:layout_marginEnd="8dp"
+        android:layout_marginBottom="8dp"
         android:contentDescription="@string/main_slim_options"
         android:padding="16dp"
-        app:layout_constraintBottom_toBottomOf="@+id/buttonDialer"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toStartOf="@+id/buttonCamera"
         app:layout_constraintStart_toEndOf="@+id/buttonDialer"
-        app:layout_constraintTop_toTopOf="@+id/buttonDialer"
         app:srcCompat="@drawable/ic_expand" />
 
-    <Button
+    <TextView
+        android:id="@+id/buttonNotes"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:alpha="0.7"
+        android:padding="8dp"
+        android:text="@string/main_options_text_notes"
+        android:textSize="24sp"
+        app:layout_constraintStart_toStartOf="@+id/mainAppsList"
+        app:layout_constraintTop_toBottomOf="@+id/mainAppsList" />
+
+    <ImageView
+        android:id="@+id/buttonDialer"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginBottom="8dp"
+        android:padding="16dp"
+        android:src="@drawable/ic_call"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        android:contentDescription="@string/main_button_dialer" />
+
+    <ImageView
         android:id="@+id/buttonCamera"
-        style="@style/Widget.AppCompat.Button.Borderless"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
         android:layout_marginBottom="8dp"
-        android:text="@string/main_button_camera"
-        android:textAppearance="@style/TextAppearance.AppCompat"
+        android:padding="16dp"
+        android:src="@drawable/ic_photo_camera"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent" />
+        app:layout_constraintEnd_toEndOf="parent"
+        android:contentDescription="@string/main_button_camera" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 1 - 2
app/src/main/res/layout/main_list_item.xml

@@ -9,10 +9,9 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
-        android:layout_marginLeft="8dp"
         android:layout_marginTop="8dp"
         android:layout_marginBottom="8dp"
-        android:textSize="44sp"
+        android:textSize="36sp"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />

+ 15 - 12
app/src/main/res/layout/note_fragment.xml

@@ -1,7 +1,7 @@
 <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:id="@+id/frameLayout3"
+    android:id="@+id/note_fragment"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:context="com.sduduzog.slimlauncher.ui.main.notes.NoteFragment">
@@ -43,33 +43,36 @@
         tools:ignore="Autofill,LabelFor" />
 
     <TextView
-        android:id="@+id/textTitle"
+        android:id="@+id/textBody"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
         android:layout_marginTop="8dp"
         android:layout_marginEnd="8dp"
         android:padding="8dp"
-        android:text="@string/note_fragment_hint_title"
-        android:textSize="24sp"
-        android:visibility="gone"
+        android:text="@string/note_fragment_hint_body"
+        android:textSize="18sp"
+        android:visibility="invisible"
         app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="1.0"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
+        app:layout_constraintTop_toBottomOf="@+id/titleEditText" />
 
     <TextView
-        android:id="@+id/textBody"
+        android:id="@+id/txtDoubleTap"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
         android:layout_marginTop="8dp"
         android:layout_marginEnd="8dp"
-        android:padding="8dp"
-        android:text="@string/note_fragment_hint_body"
-        android:textSize="18sp"
-        android:visibility="gone"
+        android:layout_marginBottom="32dp"
+        android:alpha="0.1"
+        android:gravity="center"
+        android:text="@string/double_tap_anywhere_to_edit"
+        android:textSize="30sp"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/textTitle" />
+        app:layout_constraintTop_toBottomOf="@+id/textBody" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 0 - 1
app/src/main/res/layout/notes_list_fragment.xml

@@ -4,7 +4,6 @@
     android:id="@+id/frameLayout2"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="true"
     tools:context="com.sduduzog.slimlauncher.ui.main.notes.NotesListFragment">
 
     <com.google.android.material.appbar.AppBarLayout

+ 11 - 2
app/src/main/res/navigation/nav_graph.xml

@@ -12,7 +12,15 @@
         tools:layout="@layout/main_fragment">
         <action
             android:id="@+id/action_openOptionsFragment"
-            app:destination="@id/optionsFragment" />
+            app:destination="@id/optionsFragment"
+            app:enterAnim="@anim/slide_up_enter"
+            app:exitAnim="@anim/slide_up_exit"
+            app:launchSingleTop="true"
+            app:popEnterAnim="@anim/slide_down_enter"
+            app:popExitAnim="@anim/slide_down_exit" />
+        <action
+            android:id="@+id/action_mainFragment_to_notesListFragment"
+            app:destination="@id/notesListFragment" />
     </fragment>
     <fragment
         android:id="@+id/settingsFragment"
@@ -61,7 +69,8 @@
             app:destination="@id/notesListFragment" />
         <action
             android:id="@+id/action_openSettingsFragment"
-            app:destination="@id/settingsFragment" />
+            app:destination="@id/settingsFragment"
+            app:popUpTo="@+id/mainFragment" />
         <action
             android:id="@+id/action_openAboutFragment"
             app:destination="@id/aboutFragment" />

+ 4 - 0
app/src/main/res/values/strings.xml

@@ -104,5 +104,9 @@
     <string name="title_activity_main2">Main2Activity</string>
     <string name="action_settings">Settings</string>
     <string name="section_format">Hello World from section: %1$d</string>
+    <string name="double_tap_anywhere_to_edit">Double tap anywhere to edit</string>
+
+
+    <string name="notes_date_placeholder">Edited at %s</string>
 
 </resources>