Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@

</activity>

<activity
android:name=".presentation.activity.note.PickNoteActivity"
android:exported="false">
</activity>

<receiver
android:name=".presentation.widget.WidgetProvider"
android:exported="false"
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/philkes/notallyx/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import android.os.Build
import android.preference.PreferenceManager
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.philkes.notallyx.data.model.toPreservedByteArray
import com.philkes.notallyx.data.model.toPreservedString
import com.philkes.notallyx.presentation.view.misc.AutoBackup
import com.philkes.notallyx.presentation.view.misc.AutoBackupMax
import com.philkes.notallyx.presentation.view.misc.AutoBackupPeriodDays
Expand All @@ -24,8 +26,6 @@ import com.philkes.notallyx.presentation.view.misc.TextInfo
import com.philkes.notallyx.presentation.view.misc.TextSize
import com.philkes.notallyx.presentation.view.misc.Theme
import com.philkes.notallyx.presentation.view.misc.View
import com.philkes.notallyx.utils.toPreservedByteArray
import com.philkes.notallyx.utils.toPreservedString
import java.security.SecureRandom
import javax.crypto.Cipher

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import com.philkes.notallyx.R
import com.philkes.notallyx.data.model.Attachment
import com.philkes.notallyx.data.model.Audio
import com.philkes.notallyx.data.model.FileAttachment
import com.philkes.notallyx.data.model.isImage
import com.philkes.notallyx.utils.IO.getExternalAudioDirectory
import com.philkes.notallyx.utils.IO.getExternalFilesDirectory
import com.philkes.notallyx.utils.IO.getExternalImagesDirectory
import com.philkes.notallyx.utils.isImage
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import com.philkes.notallyx.data.dao.LabelDao
import com.philkes.notallyx.data.model.BaseNote
import com.philkes.notallyx.data.model.Converters
import com.philkes.notallyx.data.model.Label
import com.philkes.notallyx.presentation.observeForeverSkipFirst
import com.philkes.notallyx.presentation.view.misc.BetterLiveData
import com.philkes.notallyx.presentation.view.misc.BiometricLock.enabled
import com.philkes.notallyx.utils.observeForeverSkipFirst
import com.philkes.notallyx.utils.security.getInitializedCipherForDecryption
import net.sqlcipher.database.SupportFactory

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.philkes.notallyx.data.model

import android.util.Patterns

fun CharSequence?.isWebUrl(): Boolean {
return this?.let { Patterns.WEB_URL.matcher(this).matches() } ?: false
}

private const val NOTE_URL_PREFIX = "note://"
private val NOTE_URL_POSTFIX_NOTE = "/${Type.NOTE.name}"
private val NOTE_URL_POSTFIX_LIST = "/${Type.LIST.name}"

fun CharSequence?.isNoteUrl(): Boolean {
return this?.let { startsWith(NOTE_URL_PREFIX) } ?: false
}

fun Long.createNoteUrl(type: Type): String {
val postfix =
when (type) {
Type.LIST -> NOTE_URL_POSTFIX_LIST
Type.NOTE -> NOTE_URL_POSTFIX_NOTE
}
return "$NOTE_URL_PREFIX$this$postfix"
}

fun String.getNoteIdFromUrl(): Long {
return substringAfter(NOTE_URL_PREFIX).substringBefore("/").toLong()
}

fun String.getNoteTypeFromUrl(): Type {
return Type.valueOf(substringAfterLast("/"))
}

fun String.getUrl(start: Int, end: Int): String {
return if (end <= length) {
substring(start, end).toUrl()
} else substring(start, length).toUrl()
}

private fun String.toUrl(): String {
return when {
matches(Patterns.PHONE.toRegex()) -> "tel:$this"
matches(Patterns.EMAIL_ADDRESS.toRegex()) -> "mailto:$this"
matches(Patterns.DOMAIN_NAME.toRegex()) -> "http://$this"
else -> this
}
}

val FileAttachment.isImage: Boolean
get() {
return mimeType.startsWith("image/")
}

val String.toPreservedByteArray: ByteArray
get() {
return this.toByteArray(Charsets.ISO_8859_1)
}

val ByteArray.toPreservedString: String
get() {
return String(this, Charsets.ISO_8859_1)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.philkes.notallyx.utils
package com.philkes.notallyx.presentation

import android.app.Activity
import android.app.KeyguardManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.pm.PackageManager
import android.content.res.Resources
Expand All @@ -24,25 +26,28 @@ import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity.INPUT_METHOD_SERVICE
import androidx.appcompat.app.AppCompatActivity.KEYGUARD_SERVICE
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.philkes.notallyx.R
import com.philkes.notallyx.data.model.FileAttachment
import com.philkes.notallyx.data.model.Folder
import com.philkes.notallyx.data.model.SpanRepresentation
import com.philkes.notallyx.presentation.activity.note.EditNoteActivity
import com.philkes.notallyx.data.model.getUrl
import com.philkes.notallyx.presentation.view.misc.DateFormat
import com.philkes.notallyx.presentation.view.misc.EditTextWithHistory
import com.philkes.notallyx.presentation.view.note.listitem.ListManager
import com.philkes.notallyx.utils.changehistory.ChangeHistory
import com.philkes.notallyx.utils.changehistory.EditTextChange
import com.philkes.notallyx.utils.changehistory.EditTextWithHistoryChange
import java.util.Date
import kotlin.math.roundToInt
import org.ocpsoft.prettytime.PrettyTime
Expand All @@ -64,7 +69,7 @@ fun String.applySpans(representations: List<SpanRepresentation>): Editable {
editable.setSpan(StyleSpan(Typeface.ITALIC), start, end)
}
if (link) {
val url = linkData ?: getURL(start, end)
val url = linkData ?: getUrl(start, end)
editable.setSpan(URLSpan(url), start, end)
}
if (monospace) {
Expand All @@ -81,7 +86,7 @@ fun String.applySpans(representations: List<SpanRepresentation>): Editable {
}

/**
* Extension function for Editable to modify or remove spans based on the selection range.
* Adjusts or removes spans based on the selection range.
*
* @param selectionStart the start index of the selection
* @param selectionEnd the end index of the selection
Expand Down Expand Up @@ -122,12 +127,6 @@ fun Editable.removeSelectionFromSpan(selectionStart: Int, selectionEnd: Int) {
}
}

private fun String.getURL(start: Int, end: Int): String {
return if (end <= length) {
EditNoteActivity.getURLFrom(substring(start, end))
} else EditNoteActivity.getURLFrom(substring(start, length))
}

private fun Spannable.setSpan(span: Any, start: Int, end: Int) {
if (end <= length) {
setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
Expand Down Expand Up @@ -226,7 +225,7 @@ fun EditText.createListTextWatcherWithHistory(listManager: ListManager, position
}
}

fun EditText.createTextWatcherWithHistory(
fun EditTextWithHistory.createTextWatcherWithHistory(
changeHistory: ChangeHistory,
onTextChanged: ((text: CharSequence, start: Int, count: Int) -> Unit)? = null,
updateModel: (text: Editable) -> Unit,
Expand All @@ -235,7 +234,7 @@ fun EditText.createTextWatcherWithHistory(
private lateinit var currentTextBefore: Editable

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
currentTextBefore = this@createTextWatcherWithHistory.text.clone()
currentTextBefore = this@createTextWatcherWithHistory.getTextClone()
}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
Expand All @@ -248,11 +247,10 @@ fun EditText.createTextWatcherWithHistory(
updateModel.invoke(textAfter)

changeHistory.push(
EditTextChange(
EditTextWithHistoryChange(
this@createTextWatcherWithHistory,
textBefore,
textAfter,
this,
updateModel,
)
)
Expand All @@ -269,11 +267,6 @@ fun View.getQuantityString(id: Int, quantity: Int, vararg formatArgs: Any): Stri
return context.resources.getQuantityString(id, quantity, *formatArgs)
}

val FileAttachment.isImage: Boolean
get() {
return mimeType.startsWith("image/")
}

fun Folder.movedToResId(): Int {
return when (this) {
Folder.DELETED -> R.plurals.deleted_selected_notes
Expand All @@ -287,7 +280,6 @@ fun RadioGroup.checkedTag(): Any {
}

fun Context.canAuthenticateWithBiometrics(): Int {
var canAuthenticate = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
val keyguardManager: KeyguardManager =
Expand All @@ -312,16 +304,6 @@ fun Context.canAuthenticateWithBiometrics(): Int {
return BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
}

val String.toPreservedByteArray: ByteArray
get() {
return this.toByteArray(Charsets.ISO_8859_1)
}

val ByteArray.toPreservedString: String
get() {
return String(this, Charsets.ISO_8859_1)
}

fun <T> LiveData<T>.observeForeverSkipFirst(observer: Observer<T>) {
var isFirstEvent = true
this.observeForever { value ->
Expand All @@ -345,3 +327,23 @@ private fun formatTimestamp(timestamp: Long, dateFormat: String): String {
else -> java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL).format(date)
}
}

fun Activity.copyToClipBoard(text: CharSequence) {
val clipboard: ClipboardManager =
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("label", text)
clipboard.setPrimaryClip(clip)
}

fun ClipboardManager.getLatestText(): CharSequence? {
return if (primaryClip!!.itemCount > 0) primaryClip!!.getItemAt(0)!!.text else null
}

fun MaterialAlertDialogBuilder.showAndFocus(view: View): AlertDialog {
val dialog = show()
view.requestFocus()
if (view is EditText) {
dialog.window?.setSoftInputMode(SOFT_INPUT_STATE_VISIBLE)
}
return dialog
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,13 @@ package com.philkes.notallyx.presentation.activity
import android.appwidget.AppWidgetManager
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.philkes.notallyx.Preferences
import com.philkes.notallyx.R
import com.philkes.notallyx.data.NotallyDatabase
import com.philkes.notallyx.data.model.BaseNote
import com.philkes.notallyx.data.model.Header
import com.philkes.notallyx.databinding.ActivityConfigureWidgetBinding
import com.philkes.notallyx.presentation.view.main.BaseNoteAdapter
import com.philkes.notallyx.presentation.view.misc.View
import com.philkes.notallyx.presentation.view.note.listitem.ListItemListener
import com.philkes.notallyx.presentation.viewmodel.BaseNoteModel
import com.philkes.notallyx.presentation.activity.note.PickNoteActivity
import com.philkes.notallyx.presentation.widget.WidgetProvider
import com.philkes.notallyx.utils.IO.getExternalImagesDirectory
import java.util.Collections
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class ConfigureWidgetActivity : LockedActivity<ActivityConfigureWidgetBinding>(), ListItemListener {
class ConfigureWidgetActivity : PickNoteActivity() {

private lateinit var adapter: BaseNoteAdapter
private val id by lazy {
intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
Expand All @@ -36,58 +19,10 @@ class ConfigureWidgetActivity : LockedActivity<ActivityConfigureWidgetBinding>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityConfigureWidgetBinding.inflate(layoutInflater)
setContentView(binding.root)

val result = Intent()
result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
setResult(RESULT_CANCELED, result)

val preferences = Preferences.getInstance(application)

adapter =
with(preferences) {
BaseNoteAdapter(
Collections.emptySet(),
dateFormat.value,
notesSorting.value.first,
textSize.value,
maxItems,
maxLines,
maxTitle,
application.getExternalImagesDirectory(),
this@ConfigureWidgetActivity,
)
}

binding.RecyclerView.apply {
adapter = this@ConfigureWidgetActivity.adapter
setHasFixedSize(true)
layoutManager =
if (preferences.view.value == View.grid) {
StaggeredGridLayoutManager(2, RecyclerView.VERTICAL)
} else LinearLayoutManager(this@ConfigureWidgetActivity)
}

val database = NotallyDatabase.getDatabase(application)

val pinned = Header(getString(R.string.pinned))
val others = Header(getString(R.string.others))

database.observe(this) {
lifecycleScope.launch {
val notes =
withContext(Dispatchers.IO) {
val raw = it.getBaseNoteDao().getAllNotes()
BaseNoteModel.transform(raw, pinned, others)
}
adapter.submitList(notes)
}
}

preferences.notesSorting.observe(this) { (sortBy, sortDirection) ->
adapter.setSorting(sortBy, sortDirection)
}
}

override fun onClick(position: Int) {
Expand All @@ -105,6 +40,4 @@ class ConfigureWidgetActivity : LockedActivity<ActivityConfigureWidgetBinding>()
finish()
}
}

override fun onLongClick(position: Int) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ import com.philkes.notallyx.databinding.DialogColorBinding
import com.philkes.notallyx.presentation.activity.LockedActivity
import com.philkes.notallyx.presentation.activity.note.EditListActivity
import com.philkes.notallyx.presentation.activity.note.EditNoteActivity
import com.philkes.notallyx.presentation.add
import com.philkes.notallyx.presentation.applySpans
import com.philkes.notallyx.presentation.movedToResId
import com.philkes.notallyx.presentation.view.main.ColorAdapter
import com.philkes.notallyx.presentation.view.misc.MenuDialog
import com.philkes.notallyx.presentation.view.note.listitem.ListItemListener
import com.philkes.notallyx.presentation.viewmodel.BaseNoteModel
import com.philkes.notallyx.utils.Operations
import com.philkes.notallyx.utils.add
import com.philkes.notallyx.utils.applySpans
import com.philkes.notallyx.utils.movedToResId
import java.io.File
import kotlinx.coroutines.launch

Expand Down
Loading