Compare commits

...

35 Commits
1.5 ... master

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
Jan-Lukas Else 4ef87824a8 1.5.1 2018-07-29 08:47:28 +02:00
Jan-Lukas Else 58490c8096 Update libraries 2018-07-29 08:39:18 +02:00
Jan-Lukas Else b80f0a0088 Update libraries 2018-05-30 17:54:33 +02:00
Jan-Lukas Else 95fbde01e6 Update Gradle Wrapper 2018-05-30 17:46:28 +02:00
23 changed files with 641 additions and 468 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,19 +2,19 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 27 compileSdkVersion 30
buildToolsVersion "27.0.3" buildToolsVersion "30.0.2"
defaultConfig { defaultConfig {
applicationId "telegra.ph" applicationId "telegra.ph"
minSdkVersion 15 minSdkVersion 19
targetSdkVersion 27 targetSdkVersion 30
versionCode 13 versionCode 18
versionName "1.5" versionName "1.5.5"
resConfigs "en" resConfigs "en", "de", "es", "tr", "ru"
} }
buildTypes { buildTypes {
debug { debug {
minifyEnabled true minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
applicationIdSuffix '.debug' applicationIdSuffix '.debug'
versionNameSuffix ' debug' versionNameSuffix ' 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.0.2' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.android.support:recyclerview-v7:27.0.2' implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'com.android.support:support-v13:27.0.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.github.delight-im:Android-AdvancedWebView:v3.0.0' 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.12.1' 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.9/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://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/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.21' ext.kotlin_version = '1.4.10'
repositories { repositories {
jcenter() jcenter()
mavenCentral() mavenCentral()
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.1' 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.17.0' id 'com.github.ben-manes.versions' version '0.33.0'
} }
allprojects { allprojects {

View File

@ -1,6 +1,6 @@
kotlin.incremental=true kotlin.incremental=true
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx3072M org.gradle.jvmargs=-Xmx3072M
android.enableD8=true android.enableD8=true
android.enableAapt2=false 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-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-bin.zip

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" "$@"

173
gradlew.bat vendored
View File

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