Compare commits

...

2 Commits

@ -50,6 +50,7 @@ import java.io.InputStreamReader
import java.lang.Thread.sleep
import java.net.URLDecoder
import java.time.Instant
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
@ -132,11 +133,12 @@ class MainActivity : AppCompatActivity() {
lateinit var ghostMetaData: ActivityResultLauncher<Intent>
lateinit var webView: WebView
lateinit var api: ghostAPI
lateinit var autosaveTimer: Timer
var ghostConnection = false
lateinit var credManager: CredentialManager
var intentScheme = "none"
var easyMDELoaded = false
var readOnResume = true
}
override fun onCreate(savedInstanceState: Bundle?) {
@ -293,24 +295,29 @@ class MainActivity : AppCompatActivity() {
checkGhostConnection()
}
ghostMetaData = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
Log.d(javaClass.simpleName,"Saving new Metadata to file")
saveFile()
}
fixedRateTimer("timer",true,0,5000){
this@MainActivity.runOnUiThread {
val script = "easyMDE.codemirror.doc.isClean();"
webView.evaluateJavascript(script , {
if (it == "false" && thisFileUri != null) {
saveFile()
}
})
}
}
}
override fun onResume() {
super.onResume()
if (!readOnResume) {
readOnResume = true
autosaveTimer = fixedRateTimer("timer",true,0,5000){
this@MainActivity.runOnUiThread {
val script = "easyMDE.codemirror.doc.isClean();"
webView.evaluateJavascript(script , {
if (it == "false" && thisFileUri != null) {
saveFile()
}
})
}
}
Log.d(javaClass.simpleName, "AutosaveTimer started.")
return
}
loadMetaFromSharedPrefs()
if (intent.data !== null) {
readFile(intent.data!!)
@ -410,7 +417,9 @@ class MainActivity : AppCompatActivity() {
R.id.push_ghost -> {
with(AlertDialog.Builder(this)){
setTitle("Push to ghostCMS?")
if (metaData.get("url") != null) setTitle("Update ghost posting to ${metaData.get("url")}?")
else setTitle("Push to ghost instance ${api.baseUrl}?")
setPositiveButton("Yes", { dialog, id ->
webView.evaluateJavascript("getHtml();", {
val msg = URLDecoder.decode(it.removeSurrounding("\""))
@ -593,12 +602,21 @@ class MainActivity : AppCompatActivity() {
val post = sendPost(title, updated_at = metaData.updatedAt!!, authors = listOf(author), html, feature_image = metaData.get("feature_image"))
val postings = sendPostList(listOf(post))
val mUrl = parse(metaData.get("url"))
val mApiHost = mUrl.scheme + "://" + mUrl.host
if (api.baseUrl != mApiHost) api = ghostAPI(applicationContext, mApiHost)
Log.d(javaClass.simpleName,"Updating post to ${mUrl}")
try {
val response = api.postApi.updatePost(id, postings).execute()
if (response.isSuccessful) {
val resp = JSONObject(response.body()!!.string())
Log.d(javaClass.simpleName, "Updated: ${resp.getJSONArray("posts").getJSONObject(0).getString("url")}")
metaData.updatedAt= resp.getJSONArray("posts").getJSONObject(0).getString("updated_at")
val intent = Intent(Intent.ACTION_VIEW).setData(parse(metaData.metaData.get("url")))
try {
startActivity(intent)
@ -608,16 +626,15 @@ class MainActivity : AppCompatActivity() {
Log.i(javaClass.simpleName, e.toString())
})
}
Log.d(javaClass.simpleName, "Updated: ${resp.getJSONArray("posts").getJSONObject(0).getString("url")}")
} else {
this.runOnUiThread({
Toast.makeText(
this,
"error while updating post.\n${response.errorBody()}",
"error while updating post.\n${response.errorBody()!!.string()}",
Toast.LENGTH_LONG
).show()
})
Log.i(javaClass.simpleName, response.code().toString())
Log.i(javaClass.simpleName, response.errorBody()!!.string())
}
return response as retrofit2.Response<Any>
} catch (ex: Exception) {
@ -929,7 +946,10 @@ class MainActivity : AppCompatActivity() {
}
fun saveFile() {
if (thisFileUri == null) return
if (thisFileUri == null) {
Log.d(javaClass.simpleName, "File Uri got null. Can't save.")
return
}
lateinit var textFile: ParcelFileDescriptor
try {
@ -982,6 +1002,7 @@ class MainActivity : AppCompatActivity() {
this.runOnUiThread({
webView.evaluateJavascript("getValue();") {
if (it == "") {
Log.d(javaClass.simpleName,"Editor delivered empty content. Don't save.")
return@evaluateJavascript
} else if (it == "null") {
Toast.makeText(
@ -995,7 +1016,7 @@ class MainActivity : AppCompatActivity() {
mdeValue =
metaData.toString() + URLDecoder.decode(it.removeSurrounding("\""))
if (mdeValue.length.toLong() == textFile.statSize) {
Log.d(javaClass.simpleName, "No change on disk, file not saved.")
Log.d(javaClass.simpleName, "No change on disk, file not saved.\n$mdeValue")
return@evaluateJavascript
}
contentResolver.openFileDescriptor(thisFileUri!!, "wt")?.use {
@ -1070,6 +1091,13 @@ class MainActivity : AppCompatActivity() {
@Throws(IOException::class)
private fun readFile(uri: Uri) {
try{
autosaveTimer.cancel()
Log.d(javaClass.simpleName, "Stopped autosaveTimer.")
} catch (e:UninitializedPropertyAccessException) {
Log.d (javaClass.simpleName, "Couldn't cancel autosaveTimer. Not yet initialized")
}
//TODO: Which permissions are really needed?
try {
contentResolver.takePersistableUriPermission(
@ -1123,6 +1151,7 @@ class MainActivity : AppCompatActivity() {
line = reader.readLine()
}
}
reader.close()
mdeValue = metaData.extractMetadataFromMarkdown(i)
if (metaData.metaData.get("url") !== null) {
val url = parse(metaData.metaData.get("url"))
@ -1192,6 +1221,17 @@ class MainActivity : AppCompatActivity() {
webView.evaluateJavascript(script, {
thisFileUri = uri
Log.d(javaClass.simpleName,"File read: ${thisFileUri}")
autosaveTimer = fixedRateTimer("timer",true,0,5000){
this@MainActivity.runOnUiThread {
val script = "easyMDE.codemirror.doc.isClean();"
webView.evaluateJavascript(script , {
if (it == "false" && thisFileUri != null) {
saveFile()
}
})
}
}
Log.d(javaClass.simpleName, "AutosaveTimer started.")
})
webView.requestFocus()
})
@ -1233,6 +1273,11 @@ class MainActivity : AppCompatActivity() {
override fun onPause() {
super.onPause()
try{
autosaveTimer.cancel()
} catch (e:Exception) {
Log.d (javaClass.simpleName, "Couldn't cancel autosaveTimer.\n$e")
}
saveFile()
webView.evaluateJavascript("easyMDE.codemirror.doc.getCursor();") {
metaData.cursor=it

@ -1,7 +1,9 @@
package org.wntr.mdeditor
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import org.wntr.mdeditor.databinding.ActivityMetadataBinding
@ -16,11 +18,23 @@ class MetadataActivity : AppCompatActivity() {
binding.title.setText(MainActivity.metaData.get("title"))
binding.url.setText(MainActivity.metaData.get("url"))
binding.featureImage.setText(MainActivity.metaData.get("feature_image"))
binding.author.setText(MainActivity.metaData.get("author") ?: MainActivity.credManager.username)
}
fun onButtonSaveClick(view: View) {
Log.d(javaClass.simpleName, "Getting Metadata:\ntitle:\t${binding.title.text}\nfeature_image:\t${binding.featureImage.text}")
MainActivity.metaData.put("title", binding.title.text.toString())
MainActivity.metaData.put("feature_image", binding.featureImage.text.toString())
if (binding.author.text.toString() != MainActivity.credManager.username) {
var apiHost: String? = null
if (MainActivity.metaData.get("url") !== null) {
val url = Uri.parse(MainActivity.metaData.get("url"))
apiHost = url.scheme + "://" + url.host
} else apiHost = MainActivity.credManager.instance
MainActivity.credManager.saveCredentialsToSharedPrefs(Credentials(apiHost, binding.author.text.toString()))
}
MainActivity.metaData.put("author", binding.author.text.toString())
MainActivity.readOnResume = false
finish()
}
}

@ -52,13 +52,13 @@ object RetrofitClient {
.baseUrl(baseUrl + "/ghost/api/admin/")
.addConverterFactory(JacksonConverterFactory.create())
.build()
}
}
class ghostAPI(applicationContext: Context, instance: String) {
val retrofit = RetrofitClient.getClient(applicationContext, instance)
val postApi = retrofit.create(PostApi::class.java)
val baseUrl = instance
fun register(credentials: Credentials): String {
@ -122,7 +122,7 @@ class ghostAPI(applicationContext: Context, instance: String) {
}
interface PostApi {
@GET("posts")
@GET("posts/")
fun getPosts(): Call<ResponseBody>
/* fun getPosts(): Call<ResponseBody> <- for json string*/

@ -29,7 +29,7 @@ class mdMeta {
if (metaData.size == 0) return ""
var metaString = "---\n"
for (key in metaData.keys) {
metaString += "$key: ${metaData.get(key as String)}\n"
if (metaData.get(key) != null) metaString += "$key: ${metaData.get(key)}\n"
}
metaString += "---\n"
return metaString
@ -39,11 +39,11 @@ class mdMeta {
fun extractMetadataFromMarkdown(markdown: String) : String {
val charactersBetweenGroupedHyphens = Regex("^---([\\s\\S]*?)---\n")
val metadataMatched = charactersBetweenGroupedHyphens.find(markdown)
ID = null
if (metadataMatched == null || metadataMatched.value == "---\n---\n") {
Log.d(javaClass.simpleName,"No metadata included")
metaData = mutableMapOf()
ID = null
return markdown
}
val metadata = metadataMatched.value

@ -4,13 +4,13 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
tools:context="MetadataActivity">
<TextView
android:id="@+id/textView2"
android:id="@+id/textView0"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="Title:"
app:layout_constraintEnd_toEndOf="@+id/barrier2"
app:layout_constraintStart_toStartOf="parent"
@ -26,14 +26,35 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/barrier2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/author"/>
<TextView
android:id="@+id/textView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Author email:"
app:layout_constraintBottom_toBottomOf="@+id/author"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/barrier2"
app:layout_constraintTop_toTopOf="@+id/author" />
<EditText
android:id="@+id/author"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints="author email"
android:inputType="text"
android:selectAllOnFocus="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/barrier2"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintBottom_toTopOf="@id/feature_image"/>
<TextView
android:id="@+id/textView3"
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="Feature Image:"
app:layout_constraintBottom_toBottomOf="@+id/feature_image"
app:layout_constraintStart_toStartOf="parent"
@ -49,19 +70,18 @@
android:selectAllOnFocus="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/barrier2"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/author"
app:layout_constraintBottom_toTopOf="@id/url"/>
<TextView
android:id="@+id/textView"
android:id="@+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="URL:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/barrier2"
app:layout_constraintTop_toTopOf="@id/url"
app:layout_constraintBottom_toBottomOf="@id/url"
android:layout_marginLeft="5dp"/>
app:layout_constraintBottom_toBottomOf="@id/url" />
<TextView
android:id="@+id/url"
@ -89,7 +109,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="textView,textView2,textView3" />
app:constraint_referenced_ids="textView0,textView1,textView2,textView3" />
</androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save