diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt index dddb7674..1873eed9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt @@ -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) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/adapters/NotesPagerAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/adapters/NotesPagerAdapter.kt index 0e89ef00..77c2a4dd 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/adapters/NotesPagerAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/adapters/NotesPagerAdapter.kt @@ -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, val activity: Activity) : FragmentStatePagerAdapter(fm) { @@ -17,14 +20,15 @@ class NotesPagerAdapter(fm: FragmentManager, val notes: List, 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, 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 { diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/databases/NotesDatabase.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/databases/NotesDatabase.kt index 26755097..849b549f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/databases/NotesDatabase.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/databases/NotesDatabase.kt @@ -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) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/ImportFolderDialog.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/ImportFolderDialog.kt index ee505e81..27758a32 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/ImportFolderDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/ImportFolderDialog.kt @@ -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) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/NewNoteDialog.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/NewNoteDialog.kt index fea01633..627489b9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/NewNoteDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/NewNoteDialog.kt @@ -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() diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/OpenFileDialog.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/OpenFileDialog.kt index c478c93b..eff35d51 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/OpenFileDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/dialogs/OpenFileDialog.kt @@ -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() } diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt new file mode 100644 index 00000000..6db97658 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt @@ -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() { + + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/NoteFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/NoteFragment.kt index 0358fc69..fced9528 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/NoteFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/NoteFragment.kt @@ -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() diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt new file mode 100644 index 00000000..750a763a --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt @@ -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()) + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/Constants.kt index a48417a0..397f5069 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/Constants.kt @@ -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 diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/NotesHelper.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/NotesHelper.kt index db3fcd29..d9b59611 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/NotesHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/helpers/NotesHelper.kt @@ -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) } diff --git a/app/src/main/res/layout/fragment_checklist.xml b/app/src/main/res/layout/fragment_checklist.xml new file mode 100644 index 00000000..d6c9bdd5 --- /dev/null +++ b/app/src/main/res/layout/fragment_checklist.xml @@ -0,0 +1,10 @@ + + diff --git a/app/src/main/res/layout/fragment_note.xml b/app/src/main/res/layout/fragment_text.xml similarity index 100% rename from app/src/main/res/layout/fragment_note.xml rename to app/src/main/res/layout/fragment_text.xml