<commit_before>package com.wbrawner.simplemarkdown.viewmodel

import android.content.Context
import android.net.Uri
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.wbrawner.simplemarkdown.utility.getName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.FileInputStream
import java.io.InputStream
import java.io.OutputStream
import java.io.Reader
import kotlin.coroutines.CoroutineContext

class MarkdownViewModel : ViewModel() {
    private val coroutineContext: CoroutineContext = Dispatchers.IO
    val fileName = MutableLiveData<String>().apply {
        postValue("Untitled.md")
    }
    val markdownUpdates = MutableLiveData<String>()
    val originalMarkdown = MutableLiveData<String>()
    val uri = MutableLiveData<Uri>()

    fun updateMarkdown(markdown: String?) {
        this.markdownUpdates.postValue(markdown ?: "")
    }

    suspend fun load(context: Context, uri: Uri?): Boolean {
        if (uri == null) return false
        return withContext(Dispatchers.IO) {
            context.contentResolver.openFileDescriptor(uri, "r")?.use {
                val fileInput = FileInputStream(it.fileDescriptor)
                val fileName = uri.getName(context)
                return@withContext if (load(fileInput)) {
                    this@MarkdownViewModel.fileName.postValue(fileName)
                    this@MarkdownViewModel.uri.postValue(uri)
                    true
                } else {
                    false
                }
            } ?: false
        }
    }

    suspend fun load(inputStream: InputStream): Boolean {
        return try {
            withContext(coroutineContext) {
                val content = inputStream.reader().use(Reader::readText)
                originalMarkdown.postValue(content)
                markdownUpdates.postValue(content)
            }
            true
        } catch (e: Throwable) {
            e.printStackTrace()
            false
        }
    }

    suspend fun save(context: Context, givenUri: Uri? = this.uri.value): Boolean {
        val uri = givenUri ?: this.uri.value ?: return false
        return withContext(Dispatchers.IO) {
            val fileName = uri.getName(context)
            val outputStream = context.contentResolver.openOutputStream(uri)
                    ?: return@withContext false
            if (save(outputStream)) {
                this@MarkdownViewModel.fileName.postValue(fileName)
                this@MarkdownViewModel.uri.postValue(uri)
                true
            } else {
                false
            }
        }
    }

    suspend fun save(outputStream: OutputStream): Boolean {
        return try {
            withContext(coroutineContext) {
                outputStream.writer().use {
                    it.write(markdownUpdates.value ?: "")
                }
            }
            true
        } catch (e: Throwable) {
            false
        }
    }

    fun reset(untitledFileName: String) {
        fileName.postValue(untitledFileName)
        originalMarkdown.postValue("")
        markdownUpdates.postValue("")<commit_msg>Simplify loading/saving files to reduce bugs<commit_after>package com.wbrawner.simplemarkdown.viewmodel

import android.content.Context
import android.net.Uri
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.wbrawner.simplemarkdown.utility.getName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.FileInputStream
import java.io.Reader
import kotlin.coroutines.CoroutineContext

class MarkdownViewModel : ViewModel() {
    private val coroutineContext: CoroutineContext = Dispatchers.IO
    val fileName = MutableLiveData<String>().apply {
        postValue("Untitled.md")
    }
    val markdownUpdates = MutableLiveData<String>()
    val originalMarkdown = MutableLiveData<String>()
    val uri = MutableLiveData<Uri>()

    fun updateMarkdown(markdown: String?) {
        this.markdownUpdates.postValue(markdown ?: "")
    }

    suspend fun load(context: Context, uri: Uri?): Boolean {
        if (uri == null) return false
        return withContext(Dispatchers.IO) {
            try {
                context.contentResolver.openFileDescriptor(uri, "r")?.use {
                    val fileInput = FileInputStream(it.fileDescriptor)
                    val fileName = uri.getName(context)
                    val content = fileInput.reader().use(Reader::readText)
                    originalMarkdown.postValue(content)
                    markdownUpdates.postValue(content)
                    this@MarkdownViewModel.fileName.postValue(fileName)
                    this@MarkdownViewModel.uri.postValue(uri)
                    true
                } ?: false
            } catch (ignored: Exception) {
                false
            }
        }
    }

    suspend fun save(context: Context, givenUri: Uri? = this.uri.value): Boolean {
        val uri = givenUri ?: this.uri.value ?: return false
        return withContext(Dispatchers.IO) {
            try {
                val fileName = uri.getName(context)
                val outputStream = context.contentResolver.openOutputStream(uri)
                        ?: return@withContext false
                outputStream.writer().use {
                    it.write(markdownUpdates.value ?: "")
                }
                this@MarkdownViewModel.fileName.postValue(fileName)
                this@MarkdownViewModel.uri.postValue(uri)
                true
            } catch (ignored: Exception) {
                false
            }
        }
    }

    fun reset(untitledFileName: String) {
        fileName.postValue(untitledFileName)
        originalMarkdown.postValue("")
        markdownUpdates.postValue("")
{'fraction_non_alphanumeric': 0.08757742601514108, 'fraction_numerical': 0.0, 'mean_word_length': 2.10855614973262, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 8, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4742964', 'n_tokens_mistral': 1548, 'n_tokens_neox': 1497, 'n_words': 280}