Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ interface CategoryDao {
@get:Query("SELECT * FROM categories GROUP BY name")
val allCategories: Flow<List<Category>>

@get:Query("SELECT * FROM categories GROUP BY name")
val allCategoriesSync: List<Category>

@Query("SELECT name FROM categories WHERE _id=:thisCategoryId ")
fun categoryNameFromId(thisCategoryId: Integer): LiveData<String?>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ package org.secuso.privacyfriendlynotes.ui.adapter
import android.app.Activity
import android.graphics.Color
import android.text.Html
import android.util.Log
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
Expand All @@ -48,6 +50,7 @@ class NoteAdapter(
var notes: MutableList<Note> = ArrayList()
private set

var saveContent: ((Note, NoteHolder) -> Unit)? = null
private var listener: ((Note, NoteHolder) -> Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val itemView = LayoutInflater.from(parent.context)
Expand Down Expand Up @@ -102,6 +105,7 @@ class NoteAdapter(
}
}

try {
when (currentNote.type) {
DbContract.NoteEntry.TYPE_TEXT -> {
if (showPreview) {
Expand All @@ -120,12 +124,23 @@ class NoteAdapter(
if (showPreview) {
holder.imageViewcategory.setBackgroundColor(run {
val value = TypedValue()
holder.itemView.context.theme.resolveAttribute(R.attr.colorSurfaceVariantLight, value, true)
holder.itemView.context.theme.resolveAttribute(
R.attr.colorSurfaceVariantLight,
value,
true
)
value.data
})
holder.imageViewcategory.minimumHeight = 200; holder.imageViewcategory.minimumWidth = 200
Glide.with(activity).load(File("${activity.application.filesDir.path}/sketches${currentNote.content}"))
.placeholder(AppCompatResources.getDrawable(activity, R.drawable.ic_photo_icon_24dp))
holder.imageViewcategory.minimumHeight =
200; holder.imageViewcategory.minimumWidth = 200
Glide.with(activity)
.load(File("${activity.application.filesDir.path}/sketches${currentNote.content}"))
.placeholder(
AppCompatResources.getDrawable(
activity,
R.drawable.ic_photo_icon_24dp
)
)
.into(holder.imageViewcategory)
} else {
holder.imageViewcategory.setImageResource(R.drawable.ic_photo_icon_24dp)
Expand All @@ -138,14 +153,24 @@ class NoteAdapter(

if (showPreview) {
val preview = mainActivityViewModel.checklistPreview(currentNote)
holder.textViewExtraText.text = "${preview.filter { it.first }.count()}/${preview.size}"
holder.textViewDescription.text = preview.take(3).joinToString(System.lineSeparator()) { it.second }
holder.textViewExtraText.text =
"${preview.filter { it.first }.count()}/${preview.size}"
holder.textViewDescription.text =
preview.take(3).joinToString(System.lineSeparator()) { it.second }
holder.textViewDescription.maxLines = 3
} else {
holder.textViewExtraText.text = "-/-"
}
}
}
} catch (error: Exception) {
Log.d("NoteAdapter", "could not preview note.")
error.printStackTrace()
holder.textViewDescription.text = ContextCompat.getString(activity, R.string.preview_note_failed)
holder.itemView.setOnClickListener {
saveContent?.let { it(currentNote, holder) }
}
}

// if the Description is empty, don't show it
if (holder.textViewDescription.text.toString().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.secuso.privacyfriendlynotes.ui.helper

import android.text.Selection
import android.text.Spannable
import android.text.method.ArrowKeyMovementMethod
import android.text.style.ClickableSpan
import android.view.MotionEvent
import android.widget.TextView

class ArrowKeyLinkTouchMovementMethod : ArrowKeyMovementMethod() {

override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
val action = event.action

if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
var x = event.x.toInt()
var y = event.y.toInt()
x -= widget.totalPaddingLeft
y -= widget.totalPaddingTop

x += widget.scrollX
y += widget.scrollY

val offset = widget.layout.let {
it.getOffsetForHorizontal(
it.getLineForVertical(y),
x.toFloat()
)
}

val link = buffer.getSpans(offset, offset, ClickableSpan::class.java)

if (link.isNotEmpty()) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget)
} else {
Selection.setSelection(
buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0])
)
}
return true
}
}
return super.onTouchEvent(widget, buffer, event)
}

companion object {
private var instance: ArrowKeyLinkTouchMovementMethod? = null

fun getInstance(): ArrowKeyLinkTouchMovementMethod {
if (instance == null) {
instance = ArrowKeyLinkTouchMovementMethod()
}
return instance!!
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.secuso.privacyfriendlynotes.ui.helper

import android.view.MotionEvent
import android.view.View
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlin.math.abs

fun FloatingActionButton.makeDraggable(target: View = this) {
var downX = 0f
var downY = 0f
var dX = 0f
var dY = 0f

val CLICK_DRAG_TOLERANCE = 10f

this.setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
downX = event.rawX
downY = event.rawY
dX = target.x - downX
dY = target.y - downY
true
}

MotionEvent.ACTION_MOVE -> {
val viewWidth = target.width
val viewHeight = target.height

val viewParent = target.parent as View
val parentWidth = viewParent.width
val parentHeight = viewParent.height

target.animate()
.x((parentWidth - viewWidth).toFloat().coerceAtMost(event.rawX + dX))
.y((parentHeight - viewHeight).toFloat().coerceAtMost(event.rawY + dY))
.setDuration(0)
.start()
true
}

MotionEvent.ACTION_UP -> {
val upRawX = event.rawX
val upRawY = event.rawY

val distanceX = upRawX - downX
val distanceY = upRawY - downY

// If the finger didn't move much, trigger a click
if (abs(distanceX) < CLICK_DRAG_TOLERANCE && abs(distanceY) < CLICK_DRAG_TOLERANCE) {
performClick()
}
true
}

else -> false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.preference.PreferenceManager
import android.text.Html
import android.util.Log
import android.util.TypedValue
import android.view.ContextThemeWrapper
Expand All @@ -35,6 +36,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.arch.core.util.Function
Expand All @@ -47,6 +49,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.navigation.NavigationView
import kotlinx.coroutines.CoroutineScope
Expand All @@ -71,6 +74,7 @@ import org.secuso.privacyfriendlynotes.ui.notes.BaseNoteActivity
import org.secuso.privacyfriendlynotes.ui.notes.ChecklistNoteActivity
import org.secuso.privacyfriendlynotes.ui.notes.SketchActivity
import org.secuso.privacyfriendlynotes.ui.notes.TextNoteActivity
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
import java.util.Collections
Expand Down Expand Up @@ -129,6 +133,35 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
}

private var noteToExport: Note? = null
private val saveSingleNoteToExternalStorageResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.data?.let { uri ->
val fileOutputStream = contentResolver.openOutputStream(uri)
if (fileOutputStream == null) {
return@registerForActivityResult
}
CoroutineScope(Dispatchers.IO).launch {
val content = when (noteToExport?.type) {
DbContract.NoteEntry.TYPE_TEXT -> noteToExport!!.content
DbContract.NoteEntry.TYPE_AUDIO -> File(filesDir.path + "/audio_notes" + noteToExport!!.content).readBytes().toString()
DbContract.NoteEntry.TYPE_SKETCH -> File(filesDir.path + "/sketches" + noteToExport!!.content).readBytes().toString()
DbContract.NoteEntry.TYPE_CHECKLIST -> noteToExport!!.content
else -> return@launch
}
fileOutputStream.bufferedWriter().write(content)
runOnUiThread {
Toast.makeText(
applicationContext,
String.format(getString(R.string.toast_file_exported_to), uri.toString()),
Toast.LENGTH_LONG
).show()
}
}
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
supportFragmentManager.fragmentFactory = object : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
Expand Down Expand Up @@ -176,6 +209,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
PreferenceManager.getDefaultSharedPreferences(this).getBoolean("settings_color_category", true)
&& mainActivityViewModel.getCategory() == CAT_ALL
)
adapter.saveContent = { note, _ ->
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.putExtra(Intent.EXTRA_TITLE, note.name + ".txt")
intent.type = "text/plain"
noteToExport = note
saveSingleNoteToExternalStorageResultLauncher.launch(intent)
}
recyclerView.adapter = adapter

lifecycleScope.launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,25 +262,28 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica

fun zipAllNotes(notes: List<Note>, output: OutputStream) {
ZipOutputStream(output).use { zipOut ->
val categories =
repository.categoryDao().allCategoriesSync.associate { it._id to it.name }.toMutableMap()
categories[CAT_ALL] = "default"
notes.forEach { note ->
val name = note.name.replace("/", "_")
lateinit var entry: String
lateinit var inputStream: InputStream
when(note.type) {
DbContract.NoteEntry.TYPE_TEXT -> {
entry = "text/" + name + "_" + System.currentTimeMillis() + "_" + TextNoteActivity.getFileExtension()
entry = categories[note.category] + "/text/" + name + "_" + note._id + "_" + TextNoteActivity.getFileExtension()
inputStream = ByteArrayInputStream(note.content.toByteArray())
}
DbContract.NoteEntry.TYPE_CHECKLIST -> {
entry = "checklist/" + name + "_" + System.currentTimeMillis() + "_" + ChecklistNoteActivity.getFileExtension()
entry = categories[note.category] + "/checklist/" + name + "_" + note._id + "_" + ChecklistNoteActivity.getFileExtension()
inputStream = ByteArrayInputStream(note.content.toByteArray())
}
DbContract.NoteEntry.TYPE_AUDIO -> {
entry = "audio/" + name + "_" + System.currentTimeMillis() + "_" + AudioNoteActivity.getFileExtension()
entry = categories[note.category] + "/audio/" + name + "_" + note._id + "_" + AudioNoteActivity.getFileExtension()
inputStream = FileInputStream(File(filesDir.path + "/audio_notes" + note.content))
}
DbContract.NoteEntry.TYPE_SKETCH -> {
entry ="sketch/" + name + "_" + System.currentTimeMillis() + "_" + SketchActivity.getFileExtension()
entry = categories[note.category] + "/sketch/" + name + "_" + note._id + "_" + SketchActivity.getFileExtension()
inputStream = FileInputStream(File(filesDir.path + "/sketches" + note.content))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,20 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli
}
}

fun newNote(content: String, type: Int, afterUpdate: (Int) -> Unit) {
saveNote(force = true)
shouldSaveOnPause = false
createEditNoteViewModel.getNoteByID(id.toLong()).observe(this) {
if (it != null) {
it.content = content
it.type = type
it._id = 0
val id = createEditNoteViewModel.insert(it)
afterUpdate(id)
}
}
}

class ActionResult<O, E>(private val status: Boolean, val ok: O?, val err: E? = null) {
fun isOk(): Boolean {
return this.status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import android.os.Bundle
import android.text.Html
import android.text.SpannedString
import android.view.ContextThemeWrapper
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.View
Expand Down Expand Up @@ -72,7 +73,7 @@ class ChecklistNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_CHECKLI

override fun onLoadActivity() {
etNewItem.setOnEditorActionListener { _, _, event ->
if (event == null && etNewItem.text.isNotEmpty()) {
if ((event == null || event.keyCode == KeyEvent.KEYCODE_ENTER) && etNewItem.text.isNotEmpty()) {
addItem()
}
return@setOnEditorActionListener true
Expand Down Expand Up @@ -140,6 +141,24 @@ class ChecklistNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_CHECKLI
}
R.id.action_select_all -> adapter.selectAll()
R.id.action_deselect_all -> adapter.deselectAll()
R.id.action_new_checked -> {
val items = adapter.getItems().filter { it.state }.map { ChecklistItem(false, it.name) }
super.newNote(ChecklistUtil.json(items).toString(), DbContract.NoteEntry.TYPE_CHECKLIST) {
val i = Intent(application, ChecklistNoteActivity::class.java)
i.putExtra(EXTRA_ID, it)
startActivity(i)
finish()
}
}
R.id.action_new_unchecked -> {
val items = adapter.getItems().filter { !it.state }
super.newNote(ChecklistUtil.json(items).toString(), DbContract.NoteEntry.TYPE_CHECKLIST) {
val i = Intent(application, ChecklistNoteActivity::class.java)
i.putExtra(EXTRA_ID, it)
startActivity(i)
finish()
}
}

else -> {}
}
Expand Down
Loading
Loading