mirror of
				https://github.com/SimpleMobileTools/Simple-Notes.git
				synced 2025-06-05 17:00:23 +02:00 
			
		
		
		
	adding a new ChecklistFragment and rename NoteFragment to TextFragment
This commit is contained in:
		| @@ -32,7 +32,7 @@ import com.simplemobiletools.notes.pro.extensions.* | ||||
| import com.simplemobiletools.notes.pro.helpers.MIME_TEXT_PLAIN | ||||
| import com.simplemobiletools.notes.pro.helpers.NotesHelper | ||||
| import com.simplemobiletools.notes.pro.helpers.OPEN_NOTE_ID | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_NOTE | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_TEXT | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| import kotlinx.android.synthetic.main.activity_main.* | ||||
| import java.io.File | ||||
| @@ -400,7 +400,7 @@ class MainActivity : SimpleActivity() { | ||||
|                 title += " (file)" | ||||
|             } | ||||
|  | ||||
|             val note = Note(null, title, "", TYPE_NOTE, path) | ||||
|             val note = Note(null, title, "", TYPE_TEXT, path) | ||||
|             addNewNote(note) | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -6,8 +6,11 @@ import android.view.ViewGroup | ||||
| import androidx.fragment.app.FragmentManager | ||||
| import androidx.fragment.app.FragmentStatePagerAdapter | ||||
| import com.simplemobiletools.commons.extensions.showErrorToast | ||||
| import com.simplemobiletools.notes.pro.fragments.ChecklistFragment | ||||
| import com.simplemobiletools.notes.pro.fragments.NoteFragment | ||||
| import com.simplemobiletools.notes.pro.fragments.TextFragment | ||||
| import com.simplemobiletools.notes.pro.helpers.NOTE_ID | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_TEXT | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
|  | ||||
| class NotesPagerAdapter(fm: FragmentManager, val notes: List<Note>, val activity: Activity) : FragmentStatePagerAdapter(fm) { | ||||
| @@ -17,14 +20,15 @@ class NotesPagerAdapter(fm: FragmentManager, val notes: List<Note>, val activity | ||||
|  | ||||
|     override fun getItem(position: Int): NoteFragment { | ||||
|         val bundle = Bundle() | ||||
|         val id = notes[position].id | ||||
|         val note = notes[position] | ||||
|         val id = note.id | ||||
|         bundle.putLong(NOTE_ID, id!!) | ||||
|  | ||||
|         if (fragments.containsKey(position)) { | ||||
|             return fragments[position]!! | ||||
|         } | ||||
|  | ||||
|         val fragment = NoteFragment() | ||||
|         val fragment = if (note.type == TYPE_TEXT) TextFragment() else ChecklistFragment() | ||||
|         fragment.arguments = bundle | ||||
|         fragments[position] = fragment | ||||
|         return fragment | ||||
| @@ -32,23 +36,23 @@ class NotesPagerAdapter(fm: FragmentManager, val notes: List<Note>, val activity | ||||
|  | ||||
|     override fun getPageTitle(position: Int) = notes[position].title | ||||
|  | ||||
|     fun getCurrentNotesView(position: Int) = fragments[position]?.getNotesView() | ||||
|     fun getCurrentNotesView(position: Int) = (fragments[position] as? TextFragment)?.getNotesView() | ||||
|  | ||||
|     fun getCurrentNoteViewText(position: Int) = fragments[position]?.getCurrentNoteViewText() | ||||
|     fun getCurrentNoteViewText(position: Int) = (fragments[position] as? TextFragment)?.getCurrentNoteViewText() | ||||
|  | ||||
|     fun appendText(position: Int, text: String) = fragments[position]?.getNotesView()?.append(text) | ||||
|     fun appendText(position: Int, text: String) = (fragments[position] as? TextFragment)?.getNotesView()?.append(text) | ||||
|  | ||||
|     fun saveCurrentNote(position: Int, force: Boolean) = fragments[position]?.saveText(force) | ||||
|     fun saveCurrentNote(position: Int, force: Boolean) = (fragments[position] as? TextFragment)?.saveText(force) | ||||
|  | ||||
|     fun focusEditText(position: Int) = fragments[position]?.focusEditText() | ||||
|     fun focusEditText(position: Int) = (fragments[position] as? TextFragment)?.focusEditText() | ||||
|  | ||||
|     fun anyHasUnsavedChanges() = fragments.values.any { it.hasUnsavedChanges() } | ||||
|     fun anyHasUnsavedChanges() = fragments.values.any { (it as? TextFragment)?.hasUnsavedChanges() == true } | ||||
|  | ||||
|     fun saveAllFragmentTexts() = fragments.values.forEach { it.saveText(false) } | ||||
|     fun saveAllFragmentTexts() = fragments.values.forEach { (it as? TextFragment)?.saveText(false) } | ||||
|  | ||||
|     fun undo(position: Int) = fragments[position]?.undo() | ||||
|     fun undo(position: Int) = (fragments[position] as? TextFragment)?.undo() | ||||
|  | ||||
|     fun redo(position: Int) = fragments[position]?.redo() | ||||
|     fun redo(position: Int) = (fragments[position] as? TextFragment)?.redo() | ||||
|  | ||||
|     override fun finishUpdate(container: ViewGroup) { | ||||
|         try { | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import androidx.room.Room | ||||
| import androidx.room.RoomDatabase | ||||
| import androidx.sqlite.db.SupportSQLiteDatabase | ||||
| import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_NOTE | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_TEXT | ||||
| import com.simplemobiletools.notes.pro.interfaces.NotesDao | ||||
| import com.simplemobiletools.notes.pro.interfaces.WidgetsDao | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| @@ -49,7 +49,7 @@ abstract class NotesDatabase : RoomDatabase() { | ||||
|         private fun insertFirstNote(context: Context) { | ||||
|             Executors.newSingleThreadScheduledExecutor().execute { | ||||
|                 val generalNote = context.resources.getString(R.string.general_note) | ||||
|                 val note = Note(null, generalNote, "", TYPE_NOTE) | ||||
|                 val note = Note(null, generalNote, "", TYPE_TEXT) | ||||
|                 db!!.NotesDao().insertOrUpdate(note) | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.activities.SimpleActivity | ||||
| import com.simplemobiletools.notes.pro.extensions.notesDB | ||||
| import com.simplemobiletools.notes.pro.helpers.NotesHelper | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_NOTE | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_TEXT | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| import kotlinx.android.synthetic.main.dialog_import_folder.view.* | ||||
| import java.io.File | ||||
| @@ -70,7 +70,7 @@ class ImportFolderDialog(val activity: SimpleActivity, val path: String, val cal | ||||
|     } | ||||
|  | ||||
|     private fun saveNote(title: String, value: String, path: String) { | ||||
|         val note = Note(null, title, value, TYPE_NOTE, path) | ||||
|         val note = Note(null, title, value, TYPE_TEXT, path) | ||||
|         NotesHelper(activity).insertOrUpdateNote(note) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import com.simplemobiletools.commons.extensions.value | ||||
| import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.extensions.notesDB | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_CHECKLIST | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_NOTE | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_TEXT | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| import kotlinx.android.synthetic.main.dialog_new_note.view.* | ||||
|  | ||||
| @@ -31,7 +31,7 @@ class NewNoteDialog(val activity: Activity, callback: (note: Note) -> Unit) { | ||||
|                                     title.isEmpty() -> activity.toast(R.string.no_title) | ||||
|                                     activity.notesDB.getNoteIdWithTitle(title) != null -> activity.toast(R.string.title_taken) | ||||
|                                     else -> { | ||||
|                                         val type = if (view.note_checklist.isChecked) TYPE_CHECKLIST else TYPE_NOTE | ||||
|                                         val type = if (view.note_checklist.isChecked) TYPE_CHECKLIST else TYPE_TEXT | ||||
|                                         val newNote = Note(null, title, "", type) | ||||
|                                         callback(newNote) | ||||
|                                         dismiss() | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import com.simplemobiletools.commons.extensions.humanizePath | ||||
| import com.simplemobiletools.commons.extensions.setupDialogStuff | ||||
| import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.activities.SimpleActivity | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_NOTE | ||||
| import com.simplemobiletools.notes.pro.helpers.TYPE_TEXT | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| import kotlinx.android.synthetic.main.dialog_open_file.* | ||||
| import kotlinx.android.synthetic.main.dialog_open_file.view.* | ||||
| @@ -45,7 +45,7 @@ class OpenFileDialog(val activity: SimpleActivity, val path: String, val callbac | ||||
|  | ||||
|     private fun saveNote(storeContent: String, storePath: String) { | ||||
|         val filename = path.getFilenameFromPath() | ||||
|         val note = Note(null, filename, storeContent, TYPE_NOTE, storePath) | ||||
|         val note = Note(null, filename, storeContent, TYPE_TEXT, storePath) | ||||
|         callback(note) | ||||
|         dialog.dismiss() | ||||
|     } | ||||
|   | ||||
| @@ -0,0 +1,38 @@ | ||||
| package com.simplemobiletools.notes.pro.fragments | ||||
|  | ||||
| import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.helpers.NOTE_ID | ||||
| import com.simplemobiletools.notes.pro.helpers.NotesHelper | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
|  | ||||
| class ChecklistFragment : NoteFragment() { | ||||
|     private var noteId = 0L | ||||
|     private var note: Note? = null | ||||
|  | ||||
|     lateinit var view: ViewGroup | ||||
|  | ||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | ||||
|         view = inflater.inflate(R.layout.fragment_checklist, container, false) as ViewGroup | ||||
|         noteId = arguments!!.getLong(NOTE_ID) | ||||
|         return view | ||||
|     } | ||||
|  | ||||
|     override fun onResume() { | ||||
|         super.onResume() | ||||
|  | ||||
|         NotesHelper(activity!!).getNoteWithId(noteId) { | ||||
|             if (it != null) { | ||||
|                 note = it | ||||
|                 setupFragment() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun setupFragment() { | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,297 +1,5 @@ | ||||
| package com.simplemobiletools.notes.pro.fragments | ||||
|  | ||||
| import android.annotation.SuppressLint | ||||
| import android.graphics.Typeface | ||||
| import android.os.Build | ||||
| import android.os.Bundle | ||||
| import android.text.Editable | ||||
| import android.text.Selection | ||||
| import android.text.TextWatcher | ||||
| import android.text.style.UnderlineSpan | ||||
| import android.text.util.Linkify | ||||
| import android.util.TypedValue | ||||
| import android.view.Gravity | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.view.inputmethod.EditorInfo | ||||
| import androidx.annotation.RequiresApi | ||||
| import com.simplemobiletools.commons.extensions.* | ||||
| import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.activities.MainActivity | ||||
| import com.simplemobiletools.notes.pro.extensions.config | ||||
| import com.simplemobiletools.notes.pro.extensions.getTextSize | ||||
| import com.simplemobiletools.notes.pro.extensions.updateWidgets | ||||
| import com.simplemobiletools.notes.pro.helpers.* | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| import com.simplemobiletools.notes.pro.models.TextHistory | ||||
| import com.simplemobiletools.notes.pro.models.TextHistoryItem | ||||
| import kotlinx.android.synthetic.main.fragment_note.* | ||||
| import kotlinx.android.synthetic.main.fragment_note.view.* | ||||
| import kotlinx.android.synthetic.main.note_view_horiz_scrollable.view.* | ||||
| import java.io.File | ||||
| import androidx.fragment.app.Fragment | ||||
|  | ||||
| // text history handling taken from https://gist.github.com/zeleven/0cfa738c1e8b65b23ff7df1fc30c9f7e | ||||
| class NoteFragment : androidx.fragment.app.Fragment() { | ||||
|     private val TEXT = "text" | ||||
|  | ||||
|     private var textHistory = TextHistory() | ||||
|     private var isUndoOrRedo = false | ||||
|     private var skipTextUpdating = false | ||||
|     private var noteId = 0L | ||||
|     private var note: Note? = null | ||||
|  | ||||
|     lateinit var view: ViewGroup | ||||
|  | ||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | ||||
|         view = inflater.inflate(R.layout.fragment_note, container, false) as ViewGroup | ||||
|         noteId = arguments!!.getLong(NOTE_ID) | ||||
|         retainInstance = true | ||||
|  | ||||
|         val layoutToInflate = if (config!!.enableLineWrap) R.layout.note_view_static else R.layout.note_view_horiz_scrollable | ||||
|         inflater.inflate(layoutToInflate, view.notes_relative_layout, true) | ||||
|         if (config!!.clickableLinks) { | ||||
|             view.notes_view.apply { | ||||
|                 linksClickable = true | ||||
|                 autoLinkMask = Linkify.WEB_URLS or Linkify.EMAIL_ADDRESSES | ||||
|                 movementMethod = MyMovementMethod.getInstance() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         view.notes_horizontal_scrollview?.onGlobalLayout { | ||||
|             view.notes_view.minWidth = view.notes_horizontal_scrollview.width | ||||
|         } | ||||
|  | ||||
|         return view | ||||
|     } | ||||
|  | ||||
|     @RequiresApi(Build.VERSION_CODES.O) | ||||
|     override fun onResume() { | ||||
|         super.onResume() | ||||
|  | ||||
|         NotesHelper(activity!!).getNoteWithId(noteId) { | ||||
|             if (it != null) { | ||||
|                 note = it | ||||
|                 setupFragment() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onPause() { | ||||
|         super.onPause() | ||||
|         if (config!!.autosaveNotes) { | ||||
|             saveText(false) | ||||
|         } | ||||
|         view.notes_view.removeTextChangedListener(textWatcher) | ||||
|     } | ||||
|  | ||||
|     override fun setMenuVisibility(menuVisible: Boolean) { | ||||
|         super.setMenuVisibility(menuVisible) | ||||
|         if (!menuVisible && noteId != 0L && config?.autosaveNotes == true) { | ||||
|             saveText(false) | ||||
|         } | ||||
|  | ||||
|         if (menuVisible && noteId != 0L) { | ||||
|             val currentText = getCurrentNoteViewText() | ||||
|             if (currentText != null) { | ||||
|                 (activity as MainActivity).currentNoteTextChanged(currentText, isUndoAvailable(), isRedoAvailable()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
|         super.onSaveInstanceState(outState) | ||||
|         if (note != null) { | ||||
|             outState.putString(TEXT, getCurrentNoteViewText()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onViewStateRestored(savedInstanceState: Bundle?) { | ||||
|         super.onViewStateRestored(savedInstanceState) | ||||
|         if (savedInstanceState != null && note != null && savedInstanceState.containsKey(TEXT)) { | ||||
|             skipTextUpdating = true | ||||
|             val newText = savedInstanceState.getString(TEXT) ?: "" | ||||
|             view.notes_view.setText(newText) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun setupFragment() { | ||||
|         val config = config ?: return | ||||
|         view.notes_view.apply { | ||||
|             typeface = if (config.monospacedFont) Typeface.MONOSPACE else Typeface.DEFAULT | ||||
|  | ||||
|             val fileContents = note!!.getNoteStoredValue() | ||||
|             if (fileContents == null) { | ||||
|                 (activity as MainActivity).deleteNote(false) | ||||
|                 return | ||||
|             } | ||||
|  | ||||
|             setColors(config.textColor, config.primaryColor, config.backgroundColor) | ||||
|             setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getTextSize()) | ||||
|             gravity = getTextGravity() | ||||
|             if (text.toString() != fileContents) { | ||||
|                 if (!skipTextUpdating) { | ||||
|                     setText(fileContents) | ||||
|                 } | ||||
|                 skipTextUpdating = false | ||||
|                 setSelection(if (config.placeCursorToEnd) text.length else 0) | ||||
|             } | ||||
|  | ||||
|             if (config.showKeyboard) { | ||||
|                 requestFocus() | ||||
|             } | ||||
|  | ||||
|             imeOptions = if (config.useIncognitoMode) { | ||||
|                 imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING | ||||
|             } else { | ||||
|                 imeOptions.removeBit(EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (config.showWordCount) { | ||||
|             view.notes_counter.beVisible() | ||||
|             view.notes_counter.setTextColor(config.textColor) | ||||
|             setWordCounter(view.notes_view.text.toString()) | ||||
|         } else { | ||||
|             view.notes_counter.beGone() | ||||
|         } | ||||
|  | ||||
|         view.notes_view.addTextChangedListener(textWatcher) | ||||
|     } | ||||
|  | ||||
|     fun getNotesView() = view.notes_view | ||||
|  | ||||
|     fun saveText(force: Boolean) { | ||||
|         if (note == null) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         if (note!!.path.isNotEmpty() && !File(note!!.path).exists()) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         if (context == null || activity == null) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         val newText = getCurrentNoteViewText() | ||||
|         val oldText = note!!.getNoteStoredValue() | ||||
|         if (newText != null && (newText != oldText || force)) { | ||||
|             note!!.value = newText | ||||
|             saveNoteValue(note!!) | ||||
|             context!!.updateWidgets() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun hasUnsavedChanges() = getCurrentNoteViewText() != note!!.getNoteStoredValue() | ||||
|  | ||||
|     fun focusEditText() { | ||||
|         view.notes_view.requestFocus() | ||||
|     } | ||||
|  | ||||
|     private fun saveNoteValue(note: Note) { | ||||
|         if (note.path.isEmpty()) { | ||||
|             NotesHelper(activity!!).insertOrUpdateNote(note) { | ||||
|                 (activity as? MainActivity)?.noteSavedSuccessfully(note.title) | ||||
|             } | ||||
|         } else { | ||||
|             val currentText = getCurrentNoteViewText() | ||||
|             if (currentText != null) { | ||||
|                 val displaySuccess = activity?.config?.displaySuccess ?: false | ||||
|                 (activity as? MainActivity)?.exportNoteValueToFile(note.path, currentText, displaySuccess) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun getCurrentNoteViewText() = view.notes_view?.text?.toString() | ||||
|  | ||||
|     @SuppressLint("RtlHardcoded") | ||||
|     private fun getTextGravity() = when (config!!.gravity) { | ||||
|         GRAVITY_CENTER -> Gravity.CENTER_HORIZONTAL | ||||
|         GRAVITY_RIGHT -> Gravity.RIGHT | ||||
|         else -> Gravity.LEFT | ||||
|     } | ||||
|  | ||||
|     private fun setWordCounter(text: String) { | ||||
|         val words = text.replace("\n", " ").split(" ") | ||||
|         notes_counter.text = words.count { it.isNotEmpty() }.toString() | ||||
|     } | ||||
|  | ||||
|     fun undo() { | ||||
|         val edit = textHistory.getPrevious() ?: return | ||||
|  | ||||
|         val text = view.notes_view.editableText | ||||
|         val start = edit.start | ||||
|         val end = start + if (edit.after != null) edit.after.length else 0 | ||||
|  | ||||
|         isUndoOrRedo = true | ||||
|         try { | ||||
|             text.replace(start, end, edit.before) | ||||
|         } catch (e: Exception) { | ||||
|             activity?.showErrorToast(e) | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         isUndoOrRedo = false | ||||
|  | ||||
|         for (span in text.getSpans(0, text.length, UnderlineSpan::class.java)) { | ||||
|             text.removeSpan(span) | ||||
|         } | ||||
|  | ||||
|         Selection.setSelection(text, if (edit.before == null) { | ||||
|             start | ||||
|         } else { | ||||
|             start + edit.before.length | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fun redo() { | ||||
|         val edit = textHistory.getNext() ?: return | ||||
|  | ||||
|         val text = view.notes_view.editableText | ||||
|         val start = edit.start | ||||
|         val end = start + if (edit.before != null) edit.before.length else 0 | ||||
|  | ||||
|         isUndoOrRedo = true | ||||
|         text.replace(start, end, edit.after) | ||||
|         isUndoOrRedo = false | ||||
|  | ||||
|         for (o in text.getSpans(0, text.length, UnderlineSpan::class.java)) { | ||||
|             text.removeSpan(o) | ||||
|         } | ||||
|  | ||||
|         Selection.setSelection(text, if (edit.after == null) { | ||||
|             start | ||||
|         } else { | ||||
|             start + edit.after.length | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fun isUndoAvailable() = textHistory.position > 0 | ||||
|  | ||||
|     fun isRedoAvailable() = textHistory.position < textHistory.history.size | ||||
|  | ||||
|     private var textWatcher: TextWatcher = object : TextWatcher { | ||||
|         private var beforeChange: CharSequence? = null | ||||
|         private var afterChange: CharSequence? = null | ||||
|  | ||||
|         override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { | ||||
|             if (!isUndoOrRedo) { | ||||
|                 beforeChange = s.subSequence(start, start + count) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { | ||||
|             if (!isUndoOrRedo) { | ||||
|                 afterChange = s.subSequence(start, start + count) | ||||
|                 textHistory.add(TextHistoryItem(start, beforeChange!!, afterChange!!)) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun afterTextChanged(editable: Editable) { | ||||
|             val text = editable.toString() | ||||
|             setWordCounter(text) | ||||
|             (activity as MainActivity).currentNoteTextChanged(text, isUndoAvailable(), isRedoAvailable()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| abstract class NoteFragment : Fragment() | ||||
|   | ||||
| @@ -0,0 +1,293 @@ | ||||
| package com.simplemobiletools.notes.pro.fragments | ||||
|  | ||||
| import android.annotation.SuppressLint | ||||
| import android.graphics.Typeface | ||||
| import android.os.Bundle | ||||
| import android.text.Editable | ||||
| import android.text.Selection | ||||
| import android.text.TextWatcher | ||||
| import android.text.style.UnderlineSpan | ||||
| import android.text.util.Linkify | ||||
| import android.util.TypedValue | ||||
| import android.view.Gravity | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.view.inputmethod.EditorInfo | ||||
| import com.simplemobiletools.commons.extensions.* | ||||
| import com.simplemobiletools.notes.pro.R | ||||
| import com.simplemobiletools.notes.pro.activities.MainActivity | ||||
| import com.simplemobiletools.notes.pro.extensions.config | ||||
| import com.simplemobiletools.notes.pro.extensions.getTextSize | ||||
| import com.simplemobiletools.notes.pro.extensions.updateWidgets | ||||
| import com.simplemobiletools.notes.pro.helpers.* | ||||
| import com.simplemobiletools.notes.pro.models.Note | ||||
| import com.simplemobiletools.notes.pro.models.TextHistory | ||||
| import com.simplemobiletools.notes.pro.models.TextHistoryItem | ||||
| import kotlinx.android.synthetic.main.fragment_text.view.* | ||||
| import kotlinx.android.synthetic.main.note_view_horiz_scrollable.view.* | ||||
| import java.io.File | ||||
|  | ||||
| // text history handling taken from https://gist.github.com/zeleven/0cfa738c1e8b65b23ff7df1fc30c9f7e | ||||
| class TextFragment : NoteFragment() { | ||||
|     private val TEXT = "text" | ||||
|  | ||||
|     private var textHistory = TextHistory() | ||||
|     private var isUndoOrRedo = false | ||||
|     private var skipTextUpdating = false | ||||
|     private var noteId = 0L | ||||
|     private var note: Note? = null | ||||
|  | ||||
|     lateinit var view: ViewGroup | ||||
|  | ||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | ||||
|         view = inflater.inflate(R.layout.fragment_text, container, false) as ViewGroup | ||||
|         noteId = arguments!!.getLong(NOTE_ID) | ||||
|         retainInstance = true | ||||
|  | ||||
|         val layoutToInflate = if (config!!.enableLineWrap) R.layout.note_view_static else R.layout.note_view_horiz_scrollable | ||||
|         inflater.inflate(layoutToInflate, view.notes_relative_layout, true) | ||||
|         if (config!!.clickableLinks) { | ||||
|             view.notes_view.apply { | ||||
|                 linksClickable = true | ||||
|                 autoLinkMask = Linkify.WEB_URLS or Linkify.EMAIL_ADDRESSES | ||||
|                 movementMethod = MyMovementMethod.getInstance() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         view.notes_horizontal_scrollview?.onGlobalLayout { | ||||
|             view.notes_view.minWidth = view.notes_horizontal_scrollview.width | ||||
|         } | ||||
|  | ||||
|         return view | ||||
|     } | ||||
|  | ||||
|     override fun onResume() { | ||||
|         super.onResume() | ||||
|  | ||||
|         NotesHelper(activity!!).getNoteWithId(noteId) { | ||||
|             if (it != null) { | ||||
|                 note = it | ||||
|                 setupFragment() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onPause() { | ||||
|         super.onPause() | ||||
|         if (config!!.autosaveNotes) { | ||||
|             saveText(false) | ||||
|         } | ||||
|         view.notes_view.removeTextChangedListener(textWatcher) | ||||
|     } | ||||
|  | ||||
|     override fun setMenuVisibility(menuVisible: Boolean) { | ||||
|         super.setMenuVisibility(menuVisible) | ||||
|         if (!menuVisible && noteId != 0L && config?.autosaveNotes == true) { | ||||
|             saveText(false) | ||||
|         } | ||||
|  | ||||
|         if (menuVisible && noteId != 0L) { | ||||
|             val currentText = getCurrentNoteViewText() | ||||
|             if (currentText != null) { | ||||
|                 (activity as MainActivity).currentNoteTextChanged(currentText, isUndoAvailable(), isRedoAvailable()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
|         super.onSaveInstanceState(outState) | ||||
|         if (note != null) { | ||||
|             outState.putString(TEXT, getCurrentNoteViewText()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onViewStateRestored(savedInstanceState: Bundle?) { | ||||
|         super.onViewStateRestored(savedInstanceState) | ||||
|         if (savedInstanceState != null && note != null && savedInstanceState.containsKey(TEXT)) { | ||||
|             skipTextUpdating = true | ||||
|             val newText = savedInstanceState.getString(TEXT) ?: "" | ||||
|             view.notes_view.setText(newText) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun setupFragment() { | ||||
|         val config = config ?: return | ||||
|         view.notes_view.apply { | ||||
|             typeface = if (config.monospacedFont) Typeface.MONOSPACE else Typeface.DEFAULT | ||||
|  | ||||
|             val fileContents = note!!.getNoteStoredValue() | ||||
|             if (fileContents == null) { | ||||
|                 (activity as MainActivity).deleteNote(false) | ||||
|                 return | ||||
|             } | ||||
|  | ||||
|             setColors(config.textColor, config.primaryColor, config.backgroundColor) | ||||
|             setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getTextSize()) | ||||
|             gravity = getTextGravity() | ||||
|             if (text.toString() != fileContents) { | ||||
|                 if (!skipTextUpdating) { | ||||
|                     setText(fileContents) | ||||
|                 } | ||||
|                 skipTextUpdating = false | ||||
|                 setSelection(if (config.placeCursorToEnd) text.length else 0) | ||||
|             } | ||||
|  | ||||
|             if (config.showKeyboard) { | ||||
|                 requestFocus() | ||||
|             } | ||||
|  | ||||
|             imeOptions = if (config.useIncognitoMode) { | ||||
|                 imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING | ||||
|             } else { | ||||
|                 imeOptions.removeBit(EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (config.showWordCount) { | ||||
|             view.notes_counter.beVisible() | ||||
|             view.notes_counter.setTextColor(config.textColor) | ||||
|             setWordCounter(view.notes_view.text.toString()) | ||||
|         } else { | ||||
|             view.notes_counter.beGone() | ||||
|         } | ||||
|  | ||||
|         view.notes_view.addTextChangedListener(textWatcher) | ||||
|     } | ||||
|  | ||||
|     fun getNotesView() = view.notes_view | ||||
|  | ||||
|     fun saveText(force: Boolean) { | ||||
|         if (note == null) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         if (note!!.path.isNotEmpty() && !File(note!!.path).exists()) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         if (context == null || activity == null) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         val newText = getCurrentNoteViewText() | ||||
|         val oldText = note!!.getNoteStoredValue() | ||||
|         if (newText != null && (newText != oldText || force)) { | ||||
|             note!!.value = newText | ||||
|             saveNoteValue(note!!) | ||||
|             context!!.updateWidgets() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun hasUnsavedChanges() = getCurrentNoteViewText() != note!!.getNoteStoredValue() | ||||
|  | ||||
|     fun focusEditText() { | ||||
|         view.notes_view.requestFocus() | ||||
|     } | ||||
|  | ||||
|     private fun saveNoteValue(note: Note) { | ||||
|         if (note.path.isEmpty()) { | ||||
|             NotesHelper(activity!!).insertOrUpdateNote(note) { | ||||
|                 (activity as? MainActivity)?.noteSavedSuccessfully(note.title) | ||||
|             } | ||||
|         } else { | ||||
|             val currentText = getCurrentNoteViewText() | ||||
|             if (currentText != null) { | ||||
|                 val displaySuccess = activity?.config?.displaySuccess ?: false | ||||
|                 (activity as? MainActivity)?.exportNoteValueToFile(note.path, currentText, displaySuccess) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun getCurrentNoteViewText() = view.notes_view?.text?.toString() | ||||
|  | ||||
|     @SuppressLint("RtlHardcoded") | ||||
|     private fun getTextGravity() = when (config!!.gravity) { | ||||
|         GRAVITY_CENTER -> Gravity.CENTER_HORIZONTAL | ||||
|         GRAVITY_RIGHT -> Gravity.RIGHT | ||||
|         else -> Gravity.LEFT | ||||
|     } | ||||
|  | ||||
|     private fun setWordCounter(text: String) { | ||||
|         val words = text.replace("\n", " ").split(" ") | ||||
|         view.notes_counter.text = words.count { it.isNotEmpty() }.toString() | ||||
|     } | ||||
|  | ||||
|     fun undo() { | ||||
|         val edit = textHistory.getPrevious() ?: return | ||||
|  | ||||
|         val text = view.notes_view.editableText | ||||
|         val start = edit.start | ||||
|         val end = start + if (edit.after != null) edit.after.length else 0 | ||||
|  | ||||
|         isUndoOrRedo = true | ||||
|         try { | ||||
|             text.replace(start, end, edit.before) | ||||
|         } catch (e: Exception) { | ||||
|             activity?.showErrorToast(e) | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         isUndoOrRedo = false | ||||
|  | ||||
|         for (span in text.getSpans(0, text.length, UnderlineSpan::class.java)) { | ||||
|             text.removeSpan(span) | ||||
|         } | ||||
|  | ||||
|         Selection.setSelection(text, if (edit.before == null) { | ||||
|             start | ||||
|         } else { | ||||
|             start + edit.before.length | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fun redo() { | ||||
|         val edit = textHistory.getNext() ?: return | ||||
|  | ||||
|         val text = view.notes_view.editableText | ||||
|         val start = edit.start | ||||
|         val end = start + if (edit.before != null) edit.before.length else 0 | ||||
|  | ||||
|         isUndoOrRedo = true | ||||
|         text.replace(start, end, edit.after) | ||||
|         isUndoOrRedo = false | ||||
|  | ||||
|         for (o in text.getSpans(0, text.length, UnderlineSpan::class.java)) { | ||||
|             text.removeSpan(o) | ||||
|         } | ||||
|  | ||||
|         Selection.setSelection(text, if (edit.after == null) { | ||||
|             start | ||||
|         } else { | ||||
|             start + edit.after.length | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fun isUndoAvailable() = textHistory.position > 0 | ||||
|  | ||||
|     fun isRedoAvailable() = textHistory.position < textHistory.history.size | ||||
|  | ||||
|     private var textWatcher: TextWatcher = object : TextWatcher { | ||||
|         private var beforeChange: CharSequence? = null | ||||
|         private var afterChange: CharSequence? = null | ||||
|  | ||||
|         override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { | ||||
|             if (!isUndoOrRedo) { | ||||
|                 beforeChange = s.subSequence(start, start + count) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { | ||||
|             if (!isUndoOrRedo) { | ||||
|                 afterChange = s.subSequence(start, start + count) | ||||
|                 textHistory.add(TextHistoryItem(start, beforeChange!!, afterChange!!)) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun afterTextChanged(editable: Editable) { | ||||
|             val text = editable.toString() | ||||
|             setWordCounter(text) | ||||
|             (activity as MainActivity).currentNoteTextChanged(text, isUndoAvailable(), isRedoAvailable()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -33,7 +33,7 @@ const val FONT_SIZE_LARGE = 2 | ||||
| const val FONT_SIZE_EXTRA_LARGE = 3 | ||||
|  | ||||
| // note types | ||||
| const val TYPE_NOTE = 0 | ||||
| const val TYPE_TEXT = 0 | ||||
| const val TYPE_CHECKLIST = 1 | ||||
|  | ||||
| // mime types | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class NotesHelper(val activity: Activity) { | ||||
|  | ||||
|             if (notes.isEmpty()) { | ||||
|                 val generalNote = activity.resources.getString(R.string.general_note) | ||||
|                 val note = Note(null, generalNote, "", TYPE_NOTE) | ||||
|                 val note = Note(null, generalNote, "", TYPE_TEXT) | ||||
|                 activity.notesDB.insertOrUpdate(note) | ||||
|                 notes.add(note) | ||||
|             } | ||||
|   | ||||
							
								
								
									
										10
									
								
								app/src/main/res/layout/fragment_checklist.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/layout/fragment_checklist.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <com.simplemobiletools.commons.views.MyRecyclerView | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:id="@+id/checklist" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:clipToPadding="false" | ||||
|     android:overScrollMode="never" | ||||
|     app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> | ||||
		Reference in New Issue
	
	Block a user