Compare commits

...

31 Commits

Author SHA1 Message Date
Jan-Lukas Else ed27844fa9 1.5.5 2020-10-31 22:16:59 +01:00
Jan-Lukas Else e99b487218 1.5.4 2019-06-07 07:51:32 +02:00
Jan-Lukas Else 792bb627c8 Update dependencies 2019-06-07 07:40:12 +02:00
Jan-Lukas Else e47cfe7d38 Update Material Dialogs 2019-03-24 15:31:30 +01:00
dependabot[bot] dda25c44ec Bump gradle from 3.3.1 to 3.3.2 (#22)
Bumps gradle from 3.3.1 to 3.3.2.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-24 15:20:41 +01:00
dependabot[bot] 0d80011ac3 Bump input from 2.0.0 to 2.0.3 (#21)
Bumps input from 2.0.0 to 2.0.3.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-01 18:32:41 +01:00
dependabot[bot] 02fb6bb3ae Bump core from 2.0.0 to 2.0.3 (#20)
Bumps core from 2.0.0 to 2.0.3.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-01 18:27:50 +01:00
dependabot[bot] a3343e1f30 Bump Android-AdvancedWebView from 3.1.3 to v3.2.0 (#15)
Bumps [Android-AdvancedWebView](https://github.com/delight-im/Android-AdvancedWebView) from 3.1.3 to v3.2.0.
- [Release notes](https://github.com/delight-im/Android-AdvancedWebView/releases)
- [Commits](https://github.com/delight-im/Android-AdvancedWebView/compare/v3.1.3...v3.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-01 18:10:10 +01:00
Jan-Lukas Else bf384a8f59 1.5.3 2019-02-10 10:59:06 +01:00
Jan-Lukas Else 1d00e34219 Small fix 2019-02-10 10:53:48 +01:00
Jan-Lukas Else 3946d21e68 Improve HTML 2019-02-10 10:46:36 +01:00
dependabot[bot] 9857315274 Bump input from 2.0.0-rc11 to 2.0.0 (#12)
Bumps input from 2.0.0-rc11 to 2.0.0.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-10 10:21:53 +01:00
dependabot[bot] cfe2950b34 Bump core from 2.0.0-rc11 to 2.0.0 (#11)
Bumps core from 2.0.0-rc11 to 2.0.0.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-10 10:19:12 +01:00
dependabot[bot] b989b775b4 Bump kotlin_version from 1.3.20 to 1.3.21 (#14)
Bumps `kotlin_version` from 1.3.20 to 1.3.21.

Updates `kotlin-gradle-plugin` from 1.3.20 to 1.3.21
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.3.20...v1.3.21)

Updates `kotlin-stdlib` from 1.3.20 to 1.3.21
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.3.20...v1.3.21)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-10 10:18:58 +01:00
dependabot[bot] 5c6476e99a Bump gradle from 3.3.0 to 3.3.1 (#13)
Bumps gradle from 3.3.0 to 3.3.1.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-10 10:18:41 +01:00
dependabot[bot] 35bada0699 Bump input from 2.0.0-rc10 to 2.0.0-rc11 (#10)
Bumps input from 2.0.0-rc10 to 2.0.0-rc11.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-06 08:23:26 +01:00
dependabot[bot] cb7f3b7dd1 Bump core from 2.0.0-rc10 to 2.0.0-rc11 (#9)
Bumps core from 2.0.0-rc10 to 2.0.0-rc11.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-06 07:58:24 +01:00
Jan-Lukas Else 2957a2f250 Fixes and improvements 2019-02-05 22:18:51 +01:00
Jan-Lukas Else c93a7ae575 Upgrade Fuel to 2.0.1 (also bump min sdk to 19 - required for update) 2019-02-05 20:58:42 +01:00
Jan-Lukas Else b17d8802a5 Update Material Dialogs Input library 2019-02-05 20:21:45 +01:00
dependabot[bot] 7ef293950e Bump core from 2.0.0-rc7 to 2.0.0-rc10 (#7)
Bumps core from 2.0.0-rc7 to 2.0.0-rc10.

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-05 20:12:10 +01:00
dependabot[bot] 07539e18d7 Bump kotlin_version from 1.3.11 to 1.3.20 (#8)
Bumps `kotlin_version` from 1.3.11 to 1.3.20.

Updates `kotlin-gradle-plugin` from 1.3.11 to 1.3.20
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.3.11...v1.3.20)

Updates `kotlin-stdlib` from 1.3.11 to 1.3.20
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.3.11...v1.3.20)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-05 20:11:43 +01:00
Licaon_Kter cb6291be6b Remove uneeded reps (#4)
...this also blocked F-Droid.
2019-02-05 19:55:02 +01:00
Jan-Lukas Else 57140d34e2 1.5.2 2019-01-23 17:36:46 +01:00
florian19982 207ef7fdf0 Added i18n for German (#3) 2018-10-06 20:40:34 +02:00
Jan-Lukas Else e4443b95dd Migrate to AndroidX 2018-09-22 08:18:57 +02:00
Jan-Lukas Else fc561cf3e5 Update Gradle wrapper 2018-09-13 21:27:08 +02:00
Jan-Lukas Else 0ec5066b18 Dependency upgrades, basic bug fixing and min API bump 2018-09-11 22:24:39 +02:00
Jan-Lukas Else 041137004c Update Gradle wrapper 2018-09-11 20:51:33 +02:00
Jan-Lukas Else b2065a0fcd
Merge pull request #2 from Poussinou/patch-1
Update README.md
2018-08-20 07:46:29 +02:00
Poussinou 3e16b85e94
Update README.md 2018-08-11 15:25:46 +02:00
23 changed files with 576 additions and 401 deletions

View File

@ -8,6 +8,13 @@ For more information about Telegra.ph visit https://telegram.org/blog/instant-vi
Please take care, that this app might be unstable due to it's early development state! Please take care, that this app might be unstable due to it's early development state!
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="90">](https://f-droid.org/packages/telegra.ph/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
alt="Get it on Google Play"
height="90">](https://play.google.com/store/apps/details?id=telegra.ph)
## LICENSE ## LICENSE
``` ```

View File

@ -2,15 +2,15 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 27 compileSdkVersion 30
buildToolsVersion "28.0.1" buildToolsVersion "30.0.2"
defaultConfig { defaultConfig {
applicationId "telegra.ph" applicationId "telegra.ph"
minSdkVersion 15 minSdkVersion 19
targetSdkVersion 27 targetSdkVersion 30
versionCode 14 versionCode 18
versionName "1.5.1" versionName "1.5.5"
resConfigs "en" resConfigs "en", "de", "es", "tr", "ru"
} }
buildTypes { buildTypes {
debug { debug {
@ -24,14 +24,19 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
lintOptions {
abortOnError false
}
} }
dependencies { dependencies {
implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'com.android.support:support-v13:27.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.github.delight-im:Android-AdvancedWebView:v3.1.3' implementation 'com.github.delight-im:Android-AdvancedWebView:3.2.1'
implementation 'com.afollestad.material-dialogs:core:0.9.6.0' implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.github.kittinunf.fuel:fuel-android:1.14.0' implementation 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'com.github.kittinunf.fuel:fuel:2.3.0'
implementation 'com.github.kittinunf.fuel:fuel-android:2.3.0'
implementation 'com.github.kittinunf.fuel:fuel-json:2.3.0'
} }

View File

@ -1,118 +1,118 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-lite.css"
rel="stylesheet"
/>
<style>
* {
max-width: 100% !important;
height: auto;
word-break: break-all;
word-break: break-word;
}
<head> #summernote {
<meta charset="utf-8"> width: 100%;
<meta http-equiv="X-UA-Compatible" content="IE=edge"> height: 100%;
<meta name="viewport" content="width=device-width, initial-scale=1"> }
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.10/summernote-lite.css" rel="stylesheet">
<style>
* {
max-width: 100% !important;
height: auto;
word-break: break-all;
word-break: break-word;
}
#summernote { .note-editor {
width: 100%; border: none !important;
height: 100%; }
} </style>
</head>
.note-editor { <body>
border: none !important; <div id="summernote"></div>
} <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</style> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-lite.min.js"></script>
</head> <script>
function domToNode(domNode) {
if (domNode.nodeType == domNode.TEXT_NODE) {
return domNode.data;
}
if (domNode.nodeType != domNode.ELEMENT_NODE) {
return false;
}
var nodeElement = {};
nodeElement.tag = domNode.tagName.toLowerCase();
for (var i = 0; i < domNode.attributes.length; i++) {
var attr = domNode.attributes[i];
if (attr.name == "href" || attr.name == "src") {
if (!nodeElement.attrs) {
nodeElement.attrs = {};
}
nodeElement.attrs[attr.name] = attr.value;
}
}
if (domNode.childNodes.length > 0) {
nodeElement.children = [];
for (var ii = 0; ii < domNode.childNodes.length; ii++) {
var child = domNode.childNodes[ii];
nodeElement.children.push(domToNode(child));
}
}
return nodeElement;
}
<body> function getNodeJson() {
<div id="summernote"></div> window.android.getText(
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> JSON.stringify(
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote-lite.min.js"></script> domToNode(document.getElementsByClassName("note-editable")[0])
<script> .children
function domToNode(domNode) { )
if (domNode.nodeType == domNode.TEXT_NODE) { );
return domNode.data; }
}
if (domNode.nodeType != domNode.ELEMENT_NODE) {
return false;
}
var nodeElement = {};
nodeElement.tag = domNode.tagName.toLowerCase();
for (var i = 0; i < domNode.attributes.length; i++) {
var attr = domNode.attributes[i];
if (attr.name == 'href' || attr.name == 'src') {
if (!nodeElement.attrs) {
nodeElement.attrs = {};
}
nodeElement.attrs[attr.name] = attr.value;
}
}
if (domNode.childNodes.length > 0) {
nodeElement.children = [];
for (var ii = 0; ii < domNode.childNodes.length; ii++) {
var child = domNode.childNodes[ii];
nodeElement.children.push(domToNode(child));
}
}
return nodeElement;
}
function getNodeJson() { function uploadImage(file) {
window.android.getText(JSON.stringify(domToNode(document.getElementsByClassName('note-editable')[0]).children)); data = new FormData();
} data.append("FileUpload", file);
$.ajax({
data: data,
type: "POST",
url: "https://telegra.ph/upload",
cache: false,
contentType: false,
processData: false,
success: function(data) {
if (data) {
$("#summernote").summernote("insertImage", data[0].src);
}
}
});
}
function uploadImage(file) { $(document).ready(function() {
data = new FormData(); $("#summernote").summernote({
data.append("FileUpload", file); focus: true,
$.ajax({ placeholder: "Start writing...",
data: data, styleTags: ["p", "h3", "h4", "blockquote", "pre"],
type: "POST", toolbar: [
url: "http://telegra.ph/upload", ["style", ["style", "bold", "italic", "underline", "clear"]],
cache: false, ["para", ["ul", "ol"]],
contentType: false, ["insert", ["link", "picture", "hr"]],
processData: false, ["history", ["undo", "redo"]],
success: function (data) { ["other", ["codeview"]]
if (data) { ],
$('#summernote').summernote('insertImage', data[0].src); callbacks: {
} onInit: function(e) {
} $("#summernote").summernote("fullscreen.toggle");
}); },
} onImageUpload: function(files) {
uploadImage(files[0]);
}
}
});
});
$(document).ready(function () { function setContent(content) {
$('#summernote').summernote({ $("#summernote").summernote("code", content);
height: 1200, }
focus: true, </script>
placeholder: 'Start writing...', </body>
styleTags: ['p', 'h3', 'h4', 'blockquote', 'pre'], </html>
toolbar: [
['style', ['style', 'bold', 'italic', 'underline', 'clear']],
['para', ['ul', 'ol']],
['insert', ['link', 'picture', 'hr']],
['history', ['undo', 'redo']],
['other', ['codeview']]
],
callbacks: {
onInit: function (e) {
$("#summernote").summernote("fullscreen.toggle");
},
onImageUpload: function (files) {
uploadImage(files[0]);
}
}
});
});
function setContent(content) {
reset();
if (content) $('#summernote').summernote('code', content);
}
function reset() {
$('#summernote').summernote('reset');
}
</script>
</body>
</html>

View File

@ -1,58 +1,60 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css"
/>
<style>
* {
max-width: 100% !important;
height: auto;
word-break: break-all;
word-break: break-word;
}
</style>
</head>
<body>
<main role="main" class="container">
<div id="viewerTitle" class="mt-3"></div>
<div id="viewerAuthor"></div>
<div id="viewerViews"></div>
<div id="viewerContent"></div>
</main>
<script>
function setTitle(title) {
document.getElementById("viewerTitle").innerHTML =
"<h1>" + title + "</h1>";
}
<head> function setAuthor(author, url) {
<meta charset="utf-8"> var viewerAuthor = document.getElementById("viewerAuthor");
<meta http-equiv="X-UA-Compatible" content="IE=edge"> if (author && url && author.length > 0 && url.length > 0)
<meta name="viewport" content="width=device-width, initial-scale=1"> viewerAuthor.innerHTML =
<link rel="stylesheet" 'By <a href="' + url + '">' + author + "</a><br>";
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"> else if (author && author.length > 0)
<style> viewerAuthor.innerHTML = "By " + author + "<br>";
* { else if (url && url.length > 0)
max-width: 100% !important; viewerAuthor.innerHTML =
height: auto; 'By <a href="' + url + '"><i>Author</i></a><br>';
word-break: break-all; else viewerAuthor.innerHTML = "";
word-break: break-word; }
}
</style> function setViews(views) {
</head> document.getElementById("viewerViews").innerHTML =
views + " times viewed<br><br>";
}
<body> function setDescription(description) {
<main role="main" class="container"> document.getElementById("viewerContent").innerHTML = description;
<div id="viewerTitle" class="mt-3"></div> }
<div id="viewerAuthor"></div>
<div id="viewerViews"></div>
<div id="viewerContent"></div>
</main>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
function setTitle(title) { function setContent(content) {
$('#viewerTitle').html('<h1>' + title + '</h1>'); document.getElementById("viewerContent").innerHTML = content;
} }
</script>
function setAuthor(author, url) { </body>
if (author && url && author.length > 0 && url.length > 0) $('#viewerAuthor').html('By <a href="' + url + '">' + author + '</a><br>'); </html>
else if (author && author.length > 0) $('#viewerAuthor').html('By ' + author + '<br>');
else if (url && url.length > 0) $('#viewerAuthor').html('By <a href="' + url + '"><i>Author</i></a><br>');
else $('#viewerAuthor').html('');
}
function setViews(views) {
$('#viewerViews').html(views + ' times viewed<br><br>');
}
function setDescription(description) {
$('#viewerContent').html(description);
}
function setContent(content) {
$('#viewerContent').html(content);
}
</script>
</body>
</html>

View File

@ -6,41 +6,33 @@ import android.util.AttributeSet
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import im.delight.android.webview.AdvancedWebView import im.delight.android.webview.AdvancedWebView
class Editor : AdvancedWebView { class Editor @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AdvancedWebView(context, attrs, defStyleAttr) {
private var getCallback: (json: String?) -> Unit? = {} private var getCallback: (json: String?) -> Unit? = {}
constructor(context: Context) : super(context) { init {
init() prepare()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init()
} }
@SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface") @SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface")
private fun init() { fun prepare() {
this.settings.javaScriptEnabled = true this.settings.javaScriptEnabled = true
this.addJavascriptInterface(MyJavaScriptInterface(), "android") this.addJavascriptInterface(MyJavaScriptInterface(), "android")
this.settings.loadWithOverviewMode = true this.settings.loadWithOverviewMode = true
this.settings.useWideViewPort = true this.settings.useWideViewPort = true
this.loadDataWithBaseURL("http://telegra.ph", context.assets.open("editor.html").bufferedReader().readText(), "text/html", "utf-8", null) setMixedContentAllowed(true)
this.loadDataWithBaseURL("https://telegra.ph", context.assets.open("editor.html").bufferedReader().readText(), "text/html", "utf-8", null)
} }
private inner class MyJavaScriptInterface { private inner class MyJavaScriptInterface {
@JavascriptInterface @JavascriptInterface
@SuppressWarnings("unused")
fun getText(json: String) { fun getText(json: String) {
getCallback(json) getCallback(json)
} }
} }
fun reset() {
this.loadUrl("javascript:reset();")
}
fun setContent(content: String?) { fun setContent(content: String?) {
this.loadUrl("javascript:setContent('${content?.replace("'", "\\'")}');") this.loadUrl("javascript:setContent('${content?.replace("'", "\\'")}');")
} }

View File

@ -4,25 +4,66 @@ import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.input.input
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import im.delight.android.webview.AdvancedWebView import im.delight.android.webview.AdvancedWebView
import java.net.URI import java.net.URI
class MainActivity : AppCompatActivity(), AdvancedWebView.Listener { class MainActivity : AppCompatActivity() {
private val viewer: Viewer? by lazy { private val viewer: Viewer? by lazy {
findViewById<Viewer?>(R.id.viewer)?.apply { findViewById<Viewer?>(R.id.viewer)?.apply {
setListener(this@MainActivity, this@MainActivity) setListener(this@MainActivity, object : AdvancedWebView.Listener {
override fun onPageFinished(url: String?) {
viewerPendingPage?.let { viewer?.showPage(it) }
viewerPendingPage = null
}
override fun onPageError(errorCode: Int, description: String?, failingUrl: String?) {
}
override fun onDownloadRequested(url: String?, suggestedFilename: String?, mimeType: String?, contentLength: Long, contentDisposition: String?, userAgent: String?) {
}
override fun onExternalPageRequest(url: String?) {
AdvancedWebView.Browsers.openUrl(this@MainActivity, url)
}
override fun onPageStarted(url: String?, favicon: Bitmap?) {
}
})
} }
} }
private var viewerPendingPage: TelegraphApi.Page? = null
private val editor: Editor? by lazy { private val editor: Editor? by lazy {
findViewById<Editor?>(R.id.editor)?.apply { findViewById<Editor?>(R.id.editor)?.apply {
setListener(this@MainActivity, this@MainActivity) setListener(this@MainActivity, object : AdvancedWebView.Listener {
override fun onPageFinished(url: String?) {
editorPendingPage?.let { editor?.setContent(it.content) }
editorPendingPage = null
}
override fun onPageError(errorCode: Int, description: String?, failingUrl: String?) {
}
override fun onDownloadRequested(url: String?, suggestedFilename: String?, mimeType: String?, contentLength: Long, contentDisposition: String?, userAgent: String?) {
}
override fun onExternalPageRequest(url: String?) {
AdvancedWebView.Browsers.openUrl(this@MainActivity, url)
}
override fun onPageStarted(url: String?, favicon: Bitmap?) {
}
})
} }
} }
private var editorPendingPage: TelegraphApi.Page? = null
private var currentPage: TelegraphApi.Page? = null private var currentPage: TelegraphApi.Page? = null
private var editorMode = true private var editorMode = true
@ -48,34 +89,43 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
} }
} }
private fun loadEditor(path: String? = null) { override fun onNewIntent(intent: Intent?) {
runOnUiThread { super.onNewIntent(intent)
editorMode = true if (intent?.action == Intent.ACTION_VIEW) {
canEdit = false val uri = URI.create(intent.dataString)
isEdit = false when (uri.host) {
invalidateOptionsMenu() "telegra.ph", "graph.org" -> loadPage(uri.path)
editor?.visibility = View.VISIBLE "edit.telegra.ph", "edit.graph.org" -> login(uri.toString())
viewer?.visibility = View.GONE
currentPage = null
// Load
if (path != null) TelegraphApi.getPage(accessToken, path, true) { success, page, error ->
if (success && page != null) {
isEdit = true
currentPage = page
editor?.setContent(page.content)
} else {
showError(error)
}
} else {
// Reset
editor?.reset()
} }
} }
} }
private fun loadEditor(path: String? = null) {
editorMode = true
canEdit = false
isEdit = false
invalidateOptionsMenu()
editor?.visibility = View.VISIBLE
viewer?.visibility = View.GONE
currentPage = null
// Load
if (path != null) TelegraphApi.getPage(accessToken, path, true) { success, page, error ->
if (success && page != null) {
isEdit = true
currentPage = page
editorPendingPage = page
editor?.prepare()
} else {
showError(error)
}
} else {
editor?.prepare()
}
}
private fun login(authUrl: String) { private fun login(authUrl: String) {
TelegraphApi.login(authUrl) { success, accessToken, account -> TelegraphApi.login(authUrl) { success, accessToken, account ->
if (success && accessToken != null) { if (success && !accessToken.isNullOrEmpty()) {
this.accessToken = accessToken this.accessToken = accessToken
this.authorName = account?.authorName this.authorName = account?.authorName
showMessage(getString(R.string.success), getString(R.string.login_success)) showMessage(getString(R.string.success), getString(R.string.login_success))
@ -84,38 +134,22 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
} }
private fun loadPage(path: String) { private fun loadPage(path: String) {
runOnUiThread { editorMode = false
editorMode = false canEdit = false
canEdit = false invalidateOptionsMenu()
invalidateOptionsMenu() viewer?.visibility = View.VISIBLE
viewer?.visibility = View.VISIBLE editor?.visibility = View.GONE
editor?.visibility = View.GONE currentPage = null
currentPage = null // Load
// Load TelegraphApi.getPage(accessToken, path, true) { success, page, error ->
TelegraphApi.getPage(accessToken, path, true) { success, page, error -> if (success && page != null) {
if (success && page != null) showPage(page) canEdit = page.canEdit ?: false
else showError(error) invalidateOptionsMenu()
} currentPage = page
} viewerPendingPage = page
} viewer?.prepare()
private fun showPage(page: TelegraphApi.Page?) {
runOnUiThread {
editorMode = false
canEdit = page?.canEdit ?: false
invalidateOptionsMenu()
viewer?.visibility = View.VISIBLE
editor?.visibility = View.GONE
currentPage = page
viewer?.clearHistory()
// Show
page?.let {
viewer?.setArticleTitle(it.title)
viewer?.setAuthor(it.authorName, it.authorUrl)
viewer?.setViews(it.views)
if (it.content == null) viewer?.setDescription(it.description)
else viewer?.setContent(it.content)
} }
else showError(error)
} }
} }
@ -123,29 +157,11 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
?: getString(R.string.error_desc)) ?: getString(R.string.error_desc))
private fun showMessage(title: String? = null, message: String? = null) { private fun showMessage(title: String? = null, message: String? = null) {
runOnUiThread { MaterialDialog(this@MainActivity)
MaterialDialog.Builder(this) .title(text = title ?: "")
.title(title ?: "") .message(text = message ?: "")
.content(message ?: "") .positiveButton(android.R.string.ok)
.positiveText(android.R.string.ok) .show()
.show()
}
}
override fun onPageFinished(url: String?) {
}
override fun onPageStarted(url: String?, favicon: Bitmap?) {
}
override fun onPageError(errorCode: Int, description: String?, failingUrl: String?) {
}
override fun onDownloadRequested(url: String?, suggestedFilename: String?, mimeType: String?, contentLength: Long, contentDisposition: String?, userAgent: String?) {
}
override fun onExternalPageRequest(url: String?) {
AdvancedWebView.Browsers.openUrl(this, url)
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -183,29 +199,29 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
} }
R.id.publish -> { R.id.publish -> {
editor?.getText { json -> editor?.getText { json ->
MaterialDialog.Builder(this) MaterialDialog(this@MainActivity)
.title(R.string.title_question) .title(R.string.title_question)
.input(getString(R.string.title_hint), currentPage?.title .input(hintRes = R.string.title_hint, prefill = currentPage?.title
?: "", { _, title -> ?: "", allowEmpty = false) { _, title ->
MaterialDialog.Builder(this) MaterialDialog(this@MainActivity)
.title(R.string.name_question) .title(R.string.name_question)
.input(getString(R.string.name_hint), if (isEdit) currentPage?.authorName .input(hintRes = R.string.name_hint, prefill = if (isEdit) currentPage?.authorName
?: authorName ?: "" else authorName ?: authorName ?: "" else authorName
?: "", { _, name -> ?: "", allowEmpty = true) { _, name ->
if (!isEdit) authorName = name.toString() if (!isEdit) authorName = name.toString()
if (isEdit) TelegraphApi.editPage(accessToken, currentPage?.path if (isEdit) TelegraphApi.editPage(accessToken, currentPage?.path
?: "", authorName = name.toString(), title = title.toString(), content = json ?: "", authorName = name.toString(), title = title.toString(), content = json
?: "", returnContent = true) { success, page, error -> ?: "", returnContent = true) { success, page, error ->
if (success && page != null) showPage(page) if (success && page != null) loadPage(page.path)
else showError(error) else showError(error)
} else TelegraphApi.createPage(accessToken, content = json } else TelegraphApi.createPage(accessToken, content = json
?: "", title = title.toString(), authorName = name.toString(), returnContent = true) { success, page, error -> ?: "", title = title.toString(), authorName = name.toString(), returnContent = true) { success, page, error ->
if (success && page != null) showPage(page) if (success && page != null) loadPage(page.path)
else showError(error) else showError(error)
} }
}) }
.show() .show()
}) }
.show() .show()
} }
true true
@ -215,24 +231,32 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
true true
} }
R.id.bookmarks -> { R.id.bookmarks -> {
MaterialDialog.Builder(this) MaterialDialog(this@MainActivity)
.title(R.string.bookmarks) .title(R.string.bookmarks)
.positiveText(android.R.string.ok) .positiveButton(R.string.open)
.items(bookmarks().reversed().map { it.second }) .negativeButton(android.R.string.cancel)
.itemsCallback { _, _, i, _ -> .listItemsSingleChoice(items = bookmarks().reversed().map { it.second }) { _, index, _ ->
loadPage(bookmarks().reversed().map { it.first }[i]) loadPage(bookmarks().reversed().map { it.first }[index])
} }
.itemsLongCallback { _, _, i, _ -> .show()
MaterialDialog.Builder(this) true
}
R.id.delete_bookmark -> {
MaterialDialog(this@MainActivity)
.title(R.string.delete_bookmark)
.positiveButton(R.string.delete)
.negativeButton(android.R.string.cancel)
.listItemsMultiChoice(items = bookmarks().reversed().map { it.second }) { _, indices, _ ->
MaterialDialog(this@MainActivity)
.title(R.string.delete) .title(R.string.delete)
.content(R.string.delete_question) .message(R.string.delete_question)
.positiveText(android.R.string.yes) .positiveButton(R.string.yes)
.negativeText(android.R.string.no) .negativeButton(R.string.no)
.onPositive { _, _ -> .positiveButton {
deleteBookmark(bookmarks().reversed().map { it.first }[i]) val tmpBookmarks = bookmarks().reversed().map { it.first }
for (index in indices) deleteBookmark(tmpBookmarks[index])
} }
.show() .show()
true
} }
.show() .show()
true true
@ -240,11 +264,11 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
R.id.published -> { R.id.published -> {
TelegraphApi.getPageList(accessToken) { success, pageList, error -> TelegraphApi.getPageList(accessToken) { success, pageList, error ->
if (success && pageList != null && pageList.pages != null) { if (success && pageList != null && pageList.pages != null) {
MaterialDialog.Builder(this) MaterialDialog(this@MainActivity)
.title(R.string.published) .title(R.string.published)
.positiveText(android.R.string.ok) .positiveButton(R.string.open)
.items(pageList.pages.map { it.title }) .negativeButton(android.R.string.cancel)
.itemsCallback { _, _, i, _ -> .listItemsSingleChoice(items = pageList.pages.map { it.title }) { _, i, _ ->
loadPage(pageList.pages[i].path) loadPage(pageList.pages[i].path)
} }
.show() .show()
@ -253,12 +277,13 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
true true
} }
R.id.bookmark -> { R.id.bookmark -> {
MaterialDialog.Builder(this) MaterialDialog(this@MainActivity)
.title(R.string.title_question) .title(R.string.title_question)
.input(getString(R.string.title_hint), "", { _, input -> .input(hintRes = R.string.title_hint, prefill = currentPage?.title
?: "", allowEmpty = false) { _, input ->
val curPage = currentPage val curPage = currentPage
if (curPage?.url != null) addBookmark(curPage.url.split("/").last(), input.toString()) if (curPage?.url != null) addBookmark(curPage.url.split("/").last(), input.toString())
}) }
.show() .show()
true true
} }
@ -271,20 +296,17 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
startActivity(Intent.createChooser(shareIntent, getString(R.string.share))) startActivity(Intent.createChooser(shareIntent, getString(R.string.share)))
true true
} }
R.id.help -> { R.id.about -> {
MaterialDialog.Builder(this) val aboutIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/jlelse/teleposter"))
.title(R.string.help) startActivity(aboutIntent)
.content(R.string.help_text, true)
.positiveText(android.R.string.ok)
.show()
true true
} }
R.id.login -> { R.id.login -> {
MaterialDialog.Builder(this) MaterialDialog(this@MainActivity)
.title(R.string.login) .title(R.string.login)
.content(R.string.login_desc) .message(R.string.login_desc)
.positiveText(android.R.string.ok) .positiveButton(android.R.string.ok)
.onPositive { _, _ -> .positiveButton {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/telegraph"))) startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/telegraph")))
} }
.show() .show()

View File

@ -1,7 +1,7 @@
package telegra.ph package telegra.ph
import android.content.Context import android.content.Context
import android.preference.PreferenceManager import androidx.preference.PreferenceManager
const val listItemSeparator = "+++;+++" const val listItemSeparator = "+++;+++"
const val itemSeparator = "xxx;xxx" const val itemSeparator = "xxx;xxx"
@ -30,7 +30,7 @@ fun Context.saveBookmarks(bookmarks: List<Pair<String, String>>) {
} }
var Context.accessToken: String var Context.accessToken: String
get() = PreferenceManager.getDefaultSharedPreferences(this).getString("accessToken", "") get() = PreferenceManager.getDefaultSharedPreferences(this).getString("accessToken", "") as String
set(value) { set(value) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putString("accessToken", value).apply() PreferenceManager.getDefaultSharedPreferences(this).edit().putString("accessToken", value).apply()
} }

View File

@ -1,14 +1,13 @@
package telegra.ph 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.FuelError
import com.github.kittinunf.fuel.core.FuelManager import com.github.kittinunf.fuel.core.FuelManager
import com.github.kittinunf.fuel.core.Request import com.github.kittinunf.fuel.core.Request
import com.github.kittinunf.fuel.core.Response import com.github.kittinunf.fuel.core.Response
import com.github.kittinunf.fuel.core.interceptors.redirectResponseInterceptor import com.github.kittinunf.fuel.core.interceptors.redirectResponseInterceptor
import com.github.kittinunf.fuel.core.interceptors.validatorResponseInterceptor
import com.github.kittinunf.fuel.httpPost import com.github.kittinunf.fuel.httpPost
import com.github.kittinunf.fuel.json.FuelJson
import com.github.kittinunf.fuel.json.responseJson
import com.github.kittinunf.result.Result import com.github.kittinunf.result.Result
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
@ -27,17 +26,16 @@ object TelegraphApi {
// Fix login // Fix login
FuelManager.instance.addResponseInterceptor { FuelManager.instance.addResponseInterceptor {
redirectResponseInterceptor(FuelManager.instance) redirectResponseInterceptor(FuelManager.instance)
validatorResponseInterceptor(200..299)
it it
} }
} }
private fun callService(method: String, parameters: List<Pair<String, Any?>>, handler: (Request, Response, Result<Json, FuelError>) -> Unit) { private fun callService(method: String, parameters: List<Pair<String, Any?>>, handler: (Request, Response, Result<FuelJson, FuelError>) -> Unit) {
val requestObject = JSONObject() val requestObject = JSONObject()
parameters.forEach { parameters.forEach {
requestObject.put(it.first, it.second) requestObject.put(it.first, it.second)
} }
method.httpPost().header("Content-Type" to "application/json").body(requestObject.toString()).responseJson(handler) method.httpPost().header(mapOf("Content-Type" to "application/json")).body(requestObject.toString()).responseJson(handler)
} }
fun createAccount(shortName: String, authorName: String? = null, authorUrl: String? = null, callback: (success: Boolean, account: Account?, error: String?) -> Unit) { fun createAccount(shortName: String, authorName: String? = null, authorUrl: String? = null, callback: (success: Boolean, account: Account?, error: String?) -> Unit) {
@ -139,6 +137,9 @@ object TelegraphApi {
if (optJSONObject(i) == null) optString(i)?.let { if (optJSONObject(i) == null) optString(i)?.let {
content += it content += it
} }
// Fix mixed content
content = content.replace("http://telegra.ph", "https://telegra.ph")
content = content.replace("http://graph.org", "https://graph.org")
} }
return content return content
} }
@ -150,7 +151,7 @@ object TelegraphApi {
// Teleposter // Teleposter
private fun <T> handleResponse(result: Result<Json, FuelError>, handler: (success: Boolean, obj: T?, error: String?) -> Unit, callback: (obj: JSONObject) -> Unit) { private fun <T> handleResponse(result: Result<FuelJson, FuelError>, handler: (success: Boolean, obj: T?, error: String?) -> Unit, callback: (obj: JSONObject) -> Unit) {
val (json, error) = result val (json, error) = result
if (error == null && json != null) { if (error == null && json != null) {
val jsonObj = json.obj() val jsonObj = json.obj()
@ -179,8 +180,8 @@ object TelegraphApi {
private fun telegraphLoginInterceptor(): (Request, Response) -> Response = private fun telegraphLoginInterceptor(): (Request, Response) -> Response =
{ _, response -> { _, response ->
response.headers["Set-Cookie"] response.headers["Set-Cookie"]
?.flatMap { HttpCookie.parse(it) } .flatMap { HttpCookie.parse(it) }
?.find { it.name == "tph_token" } .find { it.name == "tph_token" }
?.let { ?.let {
loginAccessToken = it.value loginAccessToken = it.value
} }

View File

@ -4,49 +4,53 @@ import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import android.webkit.JavascriptInterface
import im.delight.android.webview.AdvancedWebView import im.delight.android.webview.AdvancedWebView
class Viewer : AdvancedWebView { class Viewer @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AdvancedWebView(context, attrs, defStyleAttr) {
constructor(context: Context) : super(context) { init {
init() prepare()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init()
} }
@SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface") @SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface")
private fun init() { fun prepare() {
this.settings.javaScriptEnabled = true settings.javaScriptEnabled = true
this.settings.loadWithOverviewMode = true settings.loadWithOverviewMode = true
this.settings.useWideViewPort = true settings.useWideViewPort = true
overScrollMode = View.OVER_SCROLL_NEVER overScrollMode = View.OVER_SCROLL_NEVER
setMixedContentAllowed(true) setMixedContentAllowed(true)
this.loadDataWithBaseURL("http://telegra.ph", context.assets.open("viewer.html").bufferedReader().readText(), "text/html", "utf-8", null) loadDataWithBaseURL("https://telegra.ph", context.assets.open("viewer.html").bufferedReader().readText(), "text/html", "utf-8", null)
} }
fun setArticleTitle(title: String) { fun showPage(page: TelegraphApi.Page) {
clearHistory()
setArticleTitle(page.title)
setAuthor(page.authorName, page.authorUrl)
setViews(page.views)
if (page.content == null) setDescription(page.description)
else setContent(page.content)
}
private fun setArticleTitle(title: String) {
this.loadUrl("javascript:setTitle('$title');") this.loadUrl("javascript:setTitle('$title');")
} }
fun setAuthor(author: String?, url: String?) { private fun setAuthor(author: String?, url: String?) {
this.loadUrl("javascript:setAuthor('$author','$url');") this.loadUrl("javascript:setAuthor('$author','$url');")
} }
fun setViews(views: Int) { private fun setViews(views: Int) {
this.loadUrl("javascript:setViews('$views');") this.loadUrl("javascript:setViews('$views');")
} }
fun setDescription(description: String) { private fun setDescription(description: String) {
this.loadUrl("javascript:setDescription('${description.replace("\n", "<br>")}');") this.loadUrl("javascript:setDescription('${description.replace("\n", "<br>")}');")
} }
fun setContent(content: String?) { private fun setContent(content: String?) {
this.loadUrl("javascript:setContent('${content?.replace("'", "\\'")}');") this.loadUrl("javascript:setContent('${content?.replace("'", "\\'")}');")
} }

View File

@ -25,6 +25,10 @@
android:id="@+id/bookmarks" android:id="@+id/bookmarks"
android:title="@string/bookmarks" android:title="@string/bookmarks"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/delete_bookmark"
android:title="@string/delete_bookmark"
app:showAsAction="never" />
<item <item
android:id="@+id/published" android:id="@+id/published"
android:title="@string/published" android:title="@string/published"
@ -38,7 +42,7 @@
android:title="@string/login" android:title="@string/login"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/help" android:id="@+id/about"
android:title="@string/help" android:title="@string/about"
app:showAsAction="never" /> app:showAsAction="never" />
</menu> </menu>

View File

@ -0,0 +1,29 @@
<resources>
<string name="app_name">Teleposter</string>
<string name="yes">Ja</string>
<string name="no">Nein</string>
<string name="share">Teilen</string>
<string name="about">Über</string>
<string name="bookmarks">Lesezeichen</string>
<string name="bookmark_this">Als Lesezeichen setzen</string>
<string name="delete_bookmark">Lesezeichen löschen</string>
<string name="create">Neu</string>
<string name="title_question">Titel?</string>
<string name="title_hint">Fantastischer Post #1</string>
<string name="delete">Löschen</string>
<string name="delete_question">Wirklich löschen?</string>
<string name="publish">Veröffentlichen</string>
<string name="edit">Bearbeiten</string>
<string name="try_edit">Versuchen zu bearbeiten</string>
<string name="error">Fehler</string>
<string name="error_desc">Etwas unerwartetes ist passiert!</string>
<string name="published">Veröffentlichte Posts</string>
<string name="name_question">Dein Name?</string>
<string name="name_hint">Fantastischer Autor</string>
<string name="login_failed">Login fehlgeschlagen. Noch einmal versuchen!</string>
<string name="success">Erfolg</string>
<string name="login_success">Erfolgreich eingeloggt!</string>
<string name="login">Login</string>
<string name="login_desc">Öffne den Telegraph Bot in Telegram, wähle \"Login as * on this device\" und wähle Teleposter.</string>
<string name="open">Öffnen</string>
</resources>

View File

@ -0,0 +1,29 @@
<resources>
<string name="app_name">Teleposter</string>
<string name="yes"></string>
<string name="no">No</string>
<string name="share">Compartir</string>
<string name="about">Acerca de</string>
<string name="bookmarks">Favoritos</string>
<string name="bookmark_this">Añadir a favoritos</string>
<string name="delete_bookmark">Borrar favorito</string>
<string name="create">Nueva</string>
<string name="title_question">¿Título?</string>
<string name="title_hint">Entrada increíble #1</string>
<string name="delete">Borrar</string>
<string name="delete_question">¿Realmente quiere eliminar esto?</string>
<string name="publish">Publicar</string>
<string name="edit">Editar</string>
<string name="try_edit">Prueba a editar.</string>
<string name="error">Error</string>
<string name="error_desc">¡Pasó algo inesperado!</string>
<string name="published">Entradas publicadas</string>
<string name="name_question">¿Su nombre?</string>
<string name="name_hint">Awesome Writer</string>
<string name="login_failed">Login fallido. ¡Inténtelo de nuevo!</string>
<string name="success">Hecho</string>
<string name="login_success">¡Login realizado correctamente!</string>
<string name="login">Login</string>
<string name="login_desc">Abre el bot de Telegraph en Telegram, elija \"Login as * on this device\" y seleccione Teleposter.</string>
<string name="open">Abrir</string>
</resources>

View File

@ -0,0 +1,29 @@
<resources>
<string name="app_name">Teleposter</string>
<string name="yes">да</string>
<string name="no">Нет</string>
<string name="share">Поделиться</string>
<string name="about">Информация</string>
<string name="bookmarks">Закладки</string>
<string name="bookmark_this">Добавить в закладки</string>
<string name="delete_bookmark">Удалить закладку</string>
<string name="create">Новый</string>
<string name="title_question">Заглавие?</string>
<string name="title_hint">Крутой пост #1</string>
<string name="delete">Удалить</string>
<string name="delete_question">Вы действительно хотите удалить это?</string>
<string name="publish">Публикация</string>
<string name="edit">Изменить</string>
<string name="try_edit">Повторить изменение</string>
<string name="error">Ошибка</string>
<string name="error_desc">Случилось что-то неожиданное!</string>
<string name="published">Опубликованные посты</string>
<string name="name_question">Ваше имя?</string>
<string name="name_hint">Крутой писатель</string>
<string name="login_failed">Неудачный вход. Попробуй еще раз!</string>
<string name="success">Готово</string>
<string name="login_success">Вы успешно вошли!</string>
<string name="login">Вход</string>
<string name="login_desc">Откройте Telegraph bot в Telegram, выберите \"Login as * on this device\" и выберите Teleposter.</string>
<string name="open">Открыть</string>
</resources>

View File

@ -0,0 +1,29 @@
<resources>
<string name="app_name">Teleposter</string>
<string name="yes">Evet</string>
<string name="no">Hayır</string>
<string name="share">Paylaş</string>
<string name="about">Hakkında</string>
<string name="bookmarks">Yer imleri</string>
<string name="bookmark_this">Buna yer işareti koy</string>
<string name="delete_bookmark">Yer işaretini sil</string>
<string name="create">Yeni</string>
<string name="title_question">Başlık?</string>
<string name="title_hint">Harika mesaj #1</string>
<string name="delete">Sil</string>
<string name="delete_question">Bunu gerçekten silmek istiyor musun?</string>
<string name="publish">Yayınla</string>
<string name="edit">Düzenle</string>
<string name="try_edit">Düzenlemeye çalış</string>
<string name="error">Hata</string>
<string name="error_desc">Beklenmedik bir şey oldu!</string>
<string name="published">Mesaj yayınlandı</string>
<string name="name_question">Adınız?</string>
<string name="name_hint">Süper yazar</string>
<string name="login_failed">Giriş başarısız. Tekrar deneyin!</string>
<string name="success">Başarılı</string>
<string name="login_success">Başarıyla giriş yaptınız!</string>
<string name="login">Giriş</string>
<string name="login_desc">Telegram\'da Telegraph botunu açın, \"Login as * on this device\" seçeneğini ve Teleposter\'ı seçin.</string>
<string name="open"></string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">#fafafa</color> <color name="primaryColor">#fafafa</color>
<color name="colorPrimaryDark">#c7c7c7</color> <color name="primaryDarkColor">#c7c7c7</color>
<color name="colorAccent">#212121</color> <color name="primaryTextColor">#000000</color>
</resources> </resources>

View File

@ -1,11 +1,12 @@
<resources> <resources>
<string name="app_name">Teleposter</string> <string name="app_name">Teleposter</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="share">Share</string> <string name="share">Share</string>
<string name="help">Help</string> <string name="about">About</string>
<string name="help_text">
<![CDATA[<h3>Used libraries</h3><a href=\"https://github.com/afollestad/material-dialogs\">Material Dialogs</a>, <a href=\"https://github.com/kittinunf/Fuel\">Fuel</a>, <a href=\"https://github.com/delight-im/Android-AdvancedWebView\">AdvancedWebView</a><h3>About</h3>This app is made by <a href="https://jlelse.me">Jan-Lukas Else</a> and it\'s code is published on <a href="https://github.com/jlelse/teleposter">Github</a>.]]></string>
<string name="bookmarks">Bookmarks</string> <string name="bookmarks">Bookmarks</string>
<string name="bookmark_this">Bookmark this</string> <string name="bookmark_this">Bookmark this</string>
<string name="delete_bookmark">Delete Bookmark</string>
<string name="create">New</string> <string name="create">New</string>
<string name="title_question">Title?</string> <string name="title_question">Title?</string>
<string name="title_hint">Awesome Post #1</string> <string name="title_hint">Awesome Post #1</string>
@ -24,4 +25,5 @@
<string name="login_success">You successfully logged in!</string> <string name="login_success">You successfully logged in!</string>
<string name="login">Login</string> <string name="login">Login</string>
<string name="login_desc">Open the Telegraph bot in Telegram, select \"Login as * on this device\" and choose Teleposter.</string> <string name="login_desc">Open the Telegraph bot in Telegram, select \"Login as * on this device\" and choose Teleposter.</string>
<string name="open">Open</string>
</resources> </resources>

View File

@ -1,10 +1,10 @@
<resources> <resources>
<style name="AppTheme" parent="Theme.AppCompat.Light"> <style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/primaryColor</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/primaryDarkColor</item>
<item name="colorAccent">@color/colorAccent</item> <item name="android:textColorPrimary">@color/primaryTextColor</item>
<item name="android:colorBackground">@android:color/white</item> <item name="md_color_button_text">@color/primaryTextColor</item>
</style> </style>
</resources> </resources>

View File

@ -1,18 +1,18 @@
buildscript { buildscript {
ext.kotlin_version = '1.2.51' ext.kotlin_version = '1.4.10'
repositories { repositories {
jcenter() jcenter()
mavenCentral() mavenCentral()
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.3' classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
plugins { plugins {
id 'com.github.ben-manes.versions' version '0.20.0' id 'com.github.ben-manes.versions' version '0.33.0'
} }
allprojects { allprojects {

View File

@ -1,4 +1,6 @@
kotlin.incremental=true kotlin.incremental=true
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.jvmargs=-Xmx3072M org.gradle.jvmargs=-Xmx3072M
android.enableD8=true android.enableD8=true
android.useAndroidX=true
android.enableJetifier=true

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

53
gradlew vendored
View File

@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
## Gradle start up script for UN*X ## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
@ -138,19 +156,19 @@ if $cygwin ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=$((i+1)) i=`expr $i + 1`
done done
case $i in case $i in
(0) set -- ;; 0) set -- ;;
(1) set -- "$args0" ;; 1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;; 2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;; 3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " " echo " "
} }
APP_ARGS=$(save "$@") APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell