diff --git a/app/build.gradle b/app/build.gradle index 3b680e1..84d2fb2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,8 +36,4 @@ dependencies { implementation 'com.afollestad.material-dialogs:commons:0.9.6.0' implementation 'pub.devrel:easypermissions:1.1.3' implementation 'com.github.kittinunf.fuel:fuel-android:1.12.0' - implementation('com.afollestad:bridge:5.1.2') { - exclude group: 'org.json', module: 'json' - exclude group: 'com.intellij', module: 'annotations' - } } diff --git a/app/src/main/java/telegra/ph/Api.kt b/app/src/main/java/telegra/ph/Api.kt deleted file mode 100644 index c5b7b1a..0000000 --- a/app/src/main/java/telegra/ph/Api.kt +++ /dev/null @@ -1,155 +0,0 @@ -package telegra.ph - -import com.afollestad.bridge.Bridge -import com.afollestad.bridge.MultipartForm -import org.json.JSONArray -import org.json.JSONObject -import java.io.File - - -object Api { - - private val ApiBase = "https://api.telegra.ph/" - - fun getPage(path: String?, accessToken: String?, callback: (success: Boolean, page: Page?) -> Unit) { - try { - Bridge.get("${ApiBase}getPage/$path?access_token=%s&return_content=true", accessToken).asString { response, _, _ -> - if (response?.isSuccess == true) callback(true, response.asAsonObject()?.toStockJson()?.parsePageResponse()) - else callback(false, null) - } - } catch (e: Exception) { - callback(false, null) - } - } - - fun createPage(accessToken: String?, content: String?, title: String?, name: String?, callback: (success: Boolean, Page?) -> Unit) { - try { - Bridge.get("${ApiBase}createPage?access_token=%s&title=%s&author_name=%s&content=%s&return_content=true", accessToken, title, name, content).asString { response, _, _ -> - if (response?.isSuccess == true) callback(true, response.asAsonObject()?.toStockJson()?.parsePageResponse()) - else callback(false, null) - } - } catch (e: Exception) { - callback(false, null) - } - } - - fun editPage(accessToken: String?, path: String?, content: String?, title: String?, name: String?, callback: (success: Boolean, Page?) -> Unit) { - try { - Bridge.get("${ApiBase}editPage/$path?access_token=%s&title=%s&author_name=%s&content=%s&return_content=true", accessToken, title, name, content).asString { response, _, _ -> - if (response?.isSuccess == true) callback(true, response.asAsonObject()?.toStockJson()?.parsePageResponse()) - else callback(false, null) - } - } catch (e: Exception) { - callback(false, null) - } - } - - fun createAccount(callback: (accessToken: String?) -> Unit) { - try { - Bridge.get("${ApiBase}createAccount?short_name=teleposter").asString { response, _, _ -> - if (response?.isSuccess == true) callback(response.asAsonObject()?.toStockJson()?.optJSONObject("result")?.optString("access_token")) - else callback(null) - } - } catch (e: Exception) { - callback(null) - } - } - - fun getPageList(accessToken: String?, offset: Int = 0, callback: (success: Boolean, MutableList?) -> Unit) { - try { - Bridge.get("${ApiBase}getPageList?access_token=%s&limit=200&offset=$offset", accessToken).asString { response, _, _ -> - if (response?.isSuccess == true) - response.asAsonObject()?.toStockJson()?.optJSONObject("result")?.let { - val totalCount = it.optInt("total_count") - var currentCount = 200 + offset - val result = mutableListOf() - it.optJSONArray("pages")?.let { - for (i in 0 until it.length()) { - val page = it.optJSONObject(i)?.parsePage() - if (page != null) result.add(page) - } - } - if (currentCount < totalCount) { - getPageList(accessToken, currentCount) { success, pages -> - if (success && pages != null) { - result.addAll(pages) - callback(true, result) - } - if (!success) callback(false, null) - } - currentCount += 200 - } else callback(true, result) - } ?: callback(false, null) - else callback(false, null) - } - } catch (e: Exception) { - callback(false, null) - } - } - - private fun JSONObject.parsePageResponse(): Page? { - if (optBoolean("ok", false)) optJSONObject("result")?.let { return it.parsePage() } - return null - } - - private fun JSONObject.parsePage(): Page? { - val result = Page() - result.path = optString("path", "") - result.url = optString("url", "") - result.title = optString("title", "") - result.description = optString("description", "") - result.author_name = optString("author_name", "") - result.author_url = optString("author_url", "") - result.image_url = optString("image_url", "") - optJSONArray("content")?.parseContent(result) - result.views = optInt("views", 0) - result.can_edit = optBoolean("can_edit", false) - return result - } - - private fun JSONArray.parseContent(result: Page) { - for (i in 0 until length()) { - optJSONObject(i)?.let { - result.content += "<${it.optString("tag", "")}" - it.optJSONObject("attrs")?.let { - for (key in it.keys()) { - result.content += " $key=\"${it.optString(key, "")}\"" - } - } - result.content += ">" - it.optJSONArray("children")?.parseContent(result) - result.content += "" - } - if (optJSONObject(i) == null) optString(i)?.let { - result.content += it - } - } - } - - fun uploadImage(file: File, callback: (url: String?) -> Unit) { - try { - Bridge.post("http://telegra.ph/upload") - .body(MultipartForm().add("FileUpload", file)) - .asJsonArray { _, jsonArray, _ -> - val src = jsonArray?.optJSONObject(0)?.optString("src", null) - callback(src) - } - } catch (e: Exception) { - callback(null) - } - } - -} - -class Page( - var path: String = "", - var url: String = "", - var title: String = "", - var description: String = "", - var author_name: String = "", - var author_url: String = "", - var image_url: String = "", - var content: String = "", - var views: Int = 0, - var can_edit: Boolean = false -) \ No newline at end of file diff --git a/app/src/main/java/telegra/ph/MainActivity.kt b/app/src/main/java/telegra/ph/MainActivity.kt index 2b3d8b2..4aaf1e5 100644 --- a/app/src/main/java/telegra/ph/MainActivity.kt +++ b/app/src/main/java/telegra/ph/MainActivity.kt @@ -19,7 +19,7 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD private val editor: Editor? by lazy { findViewById(R.id.editor) } private var currentUrl = "" - private var currentPage: Page? = null + private var currentPage: TelegraphApi.Page? = null private var editorMode = true private var canEdit = false private var isEdit = false @@ -37,8 +37,12 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD isVerticalScrollBarEnabled = false overScrollMode = View.OVER_SCROLL_NEVER } - if (accessToken().isNullOrBlank()) Api.createAccount { accessToken -> - if (accessToken != null) saveAccessToken(accessToken) + if (accessToken().isBlank()) TelegraphApi.createAccount(shortName = "teleposter") { success, account, error -> + if (success && account != null && account.accessToken != null) { + saveAccessToken(account.accessToken) + } else { + showError(error) + } } if (intent.action == Intent.ACTION_VIEW && intent.dataString.contains("telegra.ph")) loadPage(intent.dataString.split("/").last()) else loadEditor() @@ -54,13 +58,14 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD webView?.visibility = View.GONE currentPage = null // Load - if (path != null) Api.getPage(path, accessToken()) { success, page -> - if (success) runOnUiThread { + if (path != null) TelegraphApi.getPage(accessToken(), path, true) { success, page, error -> + if (success && page != null) { isEdit = true currentPage = page - editor?.setText(page?.content ?: "") + editor?.setText(page.content ?: "") + } else { + showError(error) } - else showError() } } } @@ -74,17 +79,17 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD editor?.visibility = View.GONE currentPage = null // Load - Api.getPage(path, accessToken()) { success, page -> - if (success) showPage(page) - else showError() + TelegraphApi.getPage(accessToken(), path, true) { success, page, error -> + if (success && page != null) showPage(page) + else showError(error) } } } - private fun showPage(page: Page?) { + private fun showPage(page: TelegraphApi.Page?) { runOnUiThread { editorMode = false - canEdit = page?.can_edit ?: false + canEdit = page?.canEdit ?: false invalidateOptionsMenu() webView?.visibility = View.VISIBLE editor?.visibility = View.GONE @@ -94,10 +99,10 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD page?.let { var html = getString(R.string.viewer_html_head) html += "

${it.title}

" - if (!it.author_name.isEmpty() && !it.author_url.isBlank()) html += "${it.author_name}
" - else if (!it.author_name.isEmpty()) html += "${it.author_name}
" + if (!it.authorName.isNullOrBlank() && !it.authorUrl.isNullOrBlank()) html += "${it.authorName}
" + else if (!it.authorName.isNullOrBlank()) html += "${it.authorName}
" if (it.views != 0) html += "${it.views} times viewed

" - if (it.content.isBlank()) html += it.description.replace("\n", "
") else html += it.content + html += if (it.content.isNullOrBlank()) it.description.replace("\n", "
") else it.content html += getString(R.string.viewer_html_end) webView?.loadDataWithBaseURL(it.url, html, "text/html; charset=UTF-8", null, null) currentUrl = it.url @@ -105,11 +110,11 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD } } - private fun showError() { + private fun showError(message: String? = null) { runOnUiThread { MaterialDialog.Builder(this) .title(R.string.error) - .content(R.string.error_desc) + .content(message ?: getString(R.string.error_desc)) .positiveText(android.R.string.ok) .show() } @@ -143,8 +148,10 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD } override fun onFileSelection(p0: FileChooserDialog, file: File) { - Api.uploadImage(file) { src -> - if (src != null) editor?.addImage(src) + TelegraphApi.uploadImage(file) { success, src, error -> + if (success && src != null && src.isNotBlank()) + editor?.addImage(src) + else showError(error) } } @@ -207,18 +214,23 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD editor?.getText { json -> MaterialDialog.Builder(this) .title(R.string.title_question) - .input(getString(R.string.title_hint), currentPage?.title ?: "", { _, title -> + .input(getString(R.string.title_hint), currentPage?.title + ?: "", { _, title -> MaterialDialog.Builder(this) .title(R.string.name_question) - .input(getString(R.string.name_hint), if (isEdit) currentPage?.author_name ?: authorName() ?: "" else authorName() ?: "", { _, name -> + .input(getString(R.string.name_hint), if (isEdit) currentPage?.authorName + ?: authorName() ?: "" else authorName() + ?: "", { _, name -> if (!isEdit) saveAuthorName(name.toString()) - if (isEdit) Api.editPage(accessToken(), currentPage?.path, json, title.toString(), name.toString()) { success, page -> - if (success) showPage(page) - else showError() - } - else Api.createPage(accessToken(), json, title.toString(), name.toString()) { success, page -> - if (success) showPage(page) - else showError() + if (isEdit) TelegraphApi.editPage(accessToken(), currentPage?.path + ?: "", authorName = name.toString(), title = title.toString(), content = json + ?: "", returnContent = true) { success, page, error -> + if (success && page != null) showPage(page) + else showError(error) + } else TelegraphApi.createPage(accessToken(), content = json + ?: "", title = title.toString(), authorName = name.toString(), returnContent = true) { success, page, error -> + if (success && page != null) showPage(page) + else showError(error) } }) .show() @@ -255,18 +267,17 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD true } R.id.published -> { - Api.getPageList(accessToken()) { success, result -> - if (!success || result == null || result.isEmpty()) showError() - else { + TelegraphApi.getPageList(accessToken()) { success, pageList, error -> + if (success && pageList != null && pageList.pages != null) { MaterialDialog.Builder(this) .title(R.string.published) .positiveText(android.R.string.ok) - .items(result.map(Page::title)) + .items(pageList.pages.map { it.title }) .itemsCallback { _, _, i, _ -> - loadPage(result.map(Page::path)[i]) + loadPage(pageList.pages[i].path) } .show() - } + } else showError(error) } true } diff --git a/app/src/main/java/telegra/ph/Prefs.kt b/app/src/main/java/telegra/ph/Prefs.kt index 1e24638..2a11afa 100644 --- a/app/src/main/java/telegra/ph/Prefs.kt +++ b/app/src/main/java/telegra/ph/Prefs.kt @@ -3,7 +3,8 @@ package telegra.ph import android.content.Context import android.preference.PreferenceManager -fun Context.bookmarks(): MutableList = PreferenceManager.getDefaultSharedPreferences(this).getString("bookmarks", null)?.split("+++;+++")?.toMutableList() ?: mutableListOf("apixxx;xxxAPI Documentation") +fun Context.bookmarks(): MutableList = PreferenceManager.getDefaultSharedPreferences(this).getString("bookmarks", null)?.split("+++;+++")?.toMutableList() + ?: mutableListOf("apixxx;xxxAPI Documentation") fun Context.addBookmark(entry: String) { PreferenceManager.getDefaultSharedPreferences(this).edit().putString("bookmarks", bookmarks().apply { @@ -15,7 +16,7 @@ fun Context.deleteBookmark(path: String) { PreferenceManager.getDefaultSharedPreferences(this).edit().putString("bookmarks", bookmarks().filter { !it.contains(path) }.joinToString(separator = "+++;+++")).apply() } -fun Context.accessToken(): String? = PreferenceManager.getDefaultSharedPreferences(this).getString("accessToken", null) +fun Context.accessToken(): String = PreferenceManager.getDefaultSharedPreferences(this).getString("accessToken", "") fun Context.saveAccessToken(token: String) { PreferenceManager.getDefaultSharedPreferences(this).edit().putString("accessToken", token).apply() diff --git a/app/src/main/java/telegra/ph/TelegraphApi.kt b/app/src/main/java/telegra/ph/TelegraphApi.kt index c0da1ce..e3220a7 100644 --- a/app/src/main/java/telegra/ph/TelegraphApi.kt +++ b/app/src/main/java/telegra/ph/TelegraphApi.kt @@ -2,16 +2,15 @@ package telegra.ph import com.github.kittinunf.fuel.android.core.Json import com.github.kittinunf.fuel.android.extension.responseJson -import com.github.kittinunf.fuel.core.FuelError -import com.github.kittinunf.fuel.core.FuelManager -import com.github.kittinunf.fuel.core.Request -import com.github.kittinunf.fuel.core.Response +import com.github.kittinunf.fuel.core.* import com.github.kittinunf.fuel.httpGet +import com.github.kittinunf.fuel.httpUpload import com.github.kittinunf.result.Result import org.json.JSONArray import org.json.JSONObject +import java.io.File -class TelegraphApi { +object TelegraphApi { // Telegraph @@ -60,20 +59,20 @@ class TelegraphApi { } } - fun getPage(path: String, returnContent: Boolean? = null, callback: (success: Boolean, page: Page?, error: String?) -> Unit) { - callService("/getPage", listOf("path" to path, "return_content" to returnContent)) { _, _, result -> + fun getPage(accessToken: String? = null, path: String, returnContent: Boolean? = null, callback: (success: Boolean, page: Page?, error: String?) -> Unit) { + callService("/getPage", listOf("access_token" to accessToken, "path" to path, "return_content" to returnContent)) { _, _, result -> handleResponse(result, callback) { obj: JSONObject -> callback(true, Page(obj), null) } } } fun getPageList(accessToken: String, offset: Int? = null, limit: Int? = null, callback: (success: Boolean, page: PageList?, error: String?) -> Unit) { - callService("/getPage", listOf("access_token" to accessToken, "offset" to offset, "limit" to limit)) { _, _, result -> + callService("/getPageList", listOf("access_token" to accessToken, "offset" to offset, "limit" to limit)) { _, _, result -> handleResponse(result, callback) { obj: JSONObject -> callback(true, PageList(obj), null) } } } fun getViews(path: String, year: Int? = null, month: Int? = null, day: Int? = null, hour: Int? = null, callback: (success: Boolean, page: PageViews?, error: String?) -> Unit) { - callService("/getPage", listOf("path" to path, "year" to year, "month" to month, "day" to day, "hour" to hour)) { _, _, result -> + callService("/getViews", listOf("path" to path, "year" to year, "month" to month, "day" to day, "hour" to hour)) { _, _, result -> handleResponse(result, callback) { obj: JSONObject -> callback(true, PageViews(obj), null) } } } @@ -139,14 +138,34 @@ class TelegraphApi { if (error == null && json != null) { val jsonObj = json.obj() if (jsonObj.optBoolean("ok")) { - handler(true, null, null) - } else { callback(jsonObj.optJSONObject("result")) + } else { + handler(false, null, jsonObj.optString("error")) } } else { handler(false, null, error?.message) } } + fun uploadImage(file: File, callback: (success: Boolean, src: String?, error: String?) -> Unit) { + "http://telegra.ph/upload".httpUpload() + .dataParts { _, _ -> + listOf(DataPart(file, name = "FileUpload")) + } + .responseJson { _, _, result -> + val (json, error) = result + if (error == null && json != null) { + val jsonObj = json.array().optJSONObject(0) + val src = jsonObj?.optString("src") + if (src != null) { + callback(true, src, null) + } else { + callback(false, null, null) + } + } else { + callback(false, null, error?.message) + } + } + } } \ No newline at end of file