Compare commits

...

49 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
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
Jan-Lukas Else ac5335af86 1.5 2018-02-14 19:24:11 +01:00
Jan-Lukas Else 1a5c508414 Fix displaying author 2018-02-14 19:23:45 +01:00
Jan-Lukas Else f63385d1d1 Fix displaying author 2018-02-14 19:10:58 +01:00
Jan-Lukas Else 62bfb2059f Remove reference to unused library 2018-02-14 19:02:20 +01:00
Jan-Lukas Else c59258af1e Remove editor border 2018-02-14 19:00:37 +01:00
Jan-Lukas Else bddc725fcb Change color scheme 2018-02-14 18:57:18 +01:00
Jan-Lukas Else 72dd10a14a Add Login help, polish menu 2018-02-14 18:51:20 +01:00
Jan-Lukas Else 3e704f3080 Enable login 2018-02-14 18:13:55 +01:00
Jan-Lukas Else d82166935f Add API method to login (untested) 2018-02-12 21:56:36 +01:00
Jan-Lukas Else e9f035e260 Add some style options to editor, remove useless strings 2018-02-12 19:54:07 +01:00
Jan-Lukas Else f8bc76157a Viewer class 2018-02-12 19:36:19 +01:00
Jan-Lukas Else 459a1b98f8 Fix some editor bugs 2018-02-12 18:18:16 +01:00
Jan-Lukas Else 4ccb45df39 Move image upload to JS part 2018-02-12 17:59:30 +01:00
Jan-Lukas Else fe09e464bf Update Fuel library 2018-02-12 15:45:01 +01:00
25 changed files with 793 additions and 491 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 12 versionCode 18
versionName "1.4.1" 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,16 +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.afollestad.material-dialogs:commons:0.9.6.0' implementation 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'pub.devrel:easypermissions:1.1.3' implementation 'com.github.kittinunf.fuel:fuel:2.3.0'
implementation 'com.github.kittinunf.fuel:fuel-android:1.12.0' implementation 'com.github.kittinunf.fuel:fuel-android:2.3.0'
implementation 'com.github.kittinunf.fuel:fuel-json:2.3.0'
} }

View File

@ -32,6 +32,9 @@
<data android:scheme="http" /> <data android:scheme="http" />
<data android:scheme="https" /> <data android:scheme="https" />
<data android:host="telegra.ph" /> <data android:host="telegra.ph" />
<data android:host="graph.org" />
<data android:host="edit.telegra.ph" />
<data android:host="edit.graph.org" />
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>

View File

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

View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<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>";
}
function setAuthor(author, url) {
var viewerAuthor = document.getElementById("viewerAuthor");
if (author && url && author.length > 0 && url.length > 0)
viewerAuthor.innerHTML =
'By <a href="' + url + '">' + author + "</a><br>";
else if (author && author.length > 0)
viewerAuthor.innerHTML = "By " + author + "<br>";
else if (url && url.length > 0)
viewerAuthor.innerHTML =
'By <a href="' + url + '"><i>Author</i></a><br>';
else viewerAuthor.innerHTML = "";
}
function setViews(views) {
document.getElementById("viewerViews").innerHTML =
views + " times viewed<br><br>";
}
function setDescription(description) {
document.getElementById("viewerContent").innerHTML = description;
}
function setContent(content) {
document.getElementById("viewerContent").innerHTML = content;
}
</script>
</body>
</html>

View File

@ -4,54 +4,37 @@ import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import android.webkit.WebSettings import im.delight.android.webview.AdvancedWebView
import android.webkit.WebView
import android.webkit.WebViewClient
class Editor : WebView { 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.settings.cacheMode = WebSettings.LOAD_NO_CACHE
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 setText(html: String) { fun setContent(content: String?) {
webViewClient = object : WebViewClient() { this.loadUrl("javascript:setContent('${content?.replace("'", "\\'")}');")
override fun onPageFinished(view: WebView, url: String) {
setText(html)
}
}
this.loadUrl("javascript:$('#summernote').summernote('reset');")
this.loadUrl("javascript:$('#summernote').summernote('code', '" + html.replace("'", "\\'") + "');")
}
fun addImage(url: String) {
this.loadUrl("javascript:$('#summernote').summernote('insertImage', '$url');")
} }
fun getText(callback: (json: String?) -> Unit) { fun getText(callback: (json: String?) -> Unit) {

View File

@ -2,23 +2,69 @@ package telegra.ph
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
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.folderselector.FileChooserDialog 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 pub.devrel.easypermissions.AfterPermissionGranted import java.net.URI
import pub.devrel.easypermissions.EasyPermissions
import java.io.File
class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserDialog.FileCallback { class MainActivity : AppCompatActivity() {
private val webView: AdvancedWebView? by lazy { findViewById<AdvancedWebView?>(R.id.webView) } private val viewer: Viewer? by lazy {
private val editor: Editor? by lazy { findViewById<Editor?>(R.id.editor) } findViewById<Viewer?>(R.id.viewer)?.apply {
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 {
findViewById<Editor?>(R.id.editor)?.apply {
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 currentUrl = ""
private var currentPage: TelegraphApi.Page? = null private var currentPage: TelegraphApi.Page? = null
private var editorMode = true private var editorMode = true
private var canEdit = false private var canEdit = false
@ -27,159 +73,104 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
webView?.apply { if (accessToken.isBlank()) TelegraphApi.createAccount(shortName = "teleposter") { success, account, error ->
setListener(this@MainActivity, this@MainActivity)
setMixedContentAllowed(true)
setCookiesEnabled(true)
setThirdPartyCookiesEnabled(true)
addPermittedHostname("telegra.ph")
isHorizontalScrollBarEnabled = false
isVerticalScrollBarEnabled = false
overScrollMode = View.OVER_SCROLL_NEVER
}
if (accessToken().isBlank()) TelegraphApi.createAccount(shortName = "teleposter") { success, account, error ->
if (success && account != null && account.accessToken != null) { if (success && account != null && account.accessToken != null) {
saveAccessToken(account.accessToken) accessToken = account.accessToken
} else { } else {
showError(error) showError(error)
} }
} }
if (intent.action == Intent.ACTION_VIEW && intent.dataString.contains("telegra.ph")) loadPage(intent.dataString.split("/").last()) if (intent.action == Intent.ACTION_VIEW) {
else loadEditor() val uri = URI.create(intent.dataString)
when (uri.host) {
"telegra.ph", "graph.org" -> loadPage(uri.path)
"edit.telegra.ph", "edit.graph.org" -> login(uri.toString())
}
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent?.action == Intent.ACTION_VIEW) {
val uri = URI.create(intent.dataString)
when (uri.host) {
"telegra.ph", "graph.org" -> loadPage(uri.path)
"edit.telegra.ph", "edit.graph.org" -> login(uri.toString())
}
}
} }
private fun loadEditor(path: String? = null) { private fun loadEditor(path: String? = null) {
runOnUiThread { editorMode = true
editorMode = true canEdit = false
canEdit = false isEdit = false
isEdit = false invalidateOptionsMenu()
invalidateOptionsMenu() editor?.visibility = View.VISIBLE
editor?.visibility = View.VISIBLE viewer?.visibility = View.GONE
webView?.visibility = View.GONE currentPage = null
currentPage = null // Load
// Load if (path != null) TelegraphApi.getPage(accessToken, path, true) { success, page, error ->
if (path != null) TelegraphApi.getPage(accessToken(), path, true) { success, page, error -> if (success && page != null) {
if (success && page != null) { isEdit = true
isEdit = true currentPage = page
currentPage = page editorPendingPage = page
editor?.setText(page.content ?: "") editor?.prepare()
} else { } else {
showError(error) showError(error)
}
} }
} else {
editor?.prepare()
}
}
private fun login(authUrl: String) {
TelegraphApi.login(authUrl) { success, accessToken, account ->
if (success && !accessToken.isNullOrEmpty()) {
this.accessToken = accessToken
this.authorName = account?.authorName
showMessage(getString(R.string.success), getString(R.string.login_success))
} else showError(getString(R.string.login_failed))
} }
} }
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
webView?.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()
webView?.visibility = View.VISIBLE
editor?.visibility = View.GONE
currentPage = page
webView?.clearHistory()
// Show
page?.let {
var html = getString(R.string.viewer_html_head)
html += "<h1>${it.title}</h1>"
if (!it.authorName.isNullOrBlank() && !it.authorUrl.isNullOrBlank()) html += "<a href=\"${it.authorUrl}\">${it.authorName}</a><br>"
else if (!it.authorName.isNullOrBlank()) html += "${it.authorName}<br>"
if (it.views != 0) html += "${it.views} times viewed<br><br>"
html += if (it.content.isNullOrBlank()) it.description.replace("\n", "<br>") else it.content
html += getString(R.string.viewer_html_end)
webView?.loadDataWithBaseURL(it.url, html, "text/html; charset=UTF-8", null, null)
currentUrl = it.url
}
}
}
private fun showError(message: String? = null) {
runOnUiThread {
MaterialDialog.Builder(this)
.title(R.string.error)
.content(message ?: getString(R.string.error_desc))
.positiveText(android.R.string.ok)
.show()
}
}
@AfterPermissionGranted(100)
private fun uploadImage() {
if (EasyPermissions.hasPermissions(this, "android.permission.READ_EXTERNAL_STORAGE")) {
FileChooserDialog.Builder(this)
.mimeType("image/*")
.show(this)
} else {
EasyPermissions.requestPermissions(this, "", 100, "android.permission.READ_EXTERNAL_STORAGE")
}
}
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 onFileSelection(p0: FileChooserDialog, file: File) {
TelegraphApi.uploadImage(file) { success, src, error ->
if (success && src != null && src.isNotBlank())
editor?.addImage(src)
else showError(error) else showError(error)
} }
} }
override fun onFileChooserDismissed(p0: FileChooserDialog) { private fun showError(message: String? = null) = showMessage(getString(R.string.error), message
} ?: getString(R.string.error_desc))
override fun onResume() { private fun showMessage(title: String? = null, message: String? = null) {
super.onResume() MaterialDialog(this@MainActivity)
webView?.onResume() .title(text = title ?: "")
} .message(text = message ?: "")
.positiveButton(android.R.string.ok)
override fun onPause() { .show()
webView?.onPause()
super.onPause()
}
override fun onDestroy() {
webView?.onDestroy()
super.onDestroy()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
webView?.onActivityResult(requestCode, resultCode, data) editor?.onActivityResult(requestCode, resultCode, data)
} }
override fun onBackPressed() { override fun onBackPressed() {
if (webView?.onBackPressed() == false) return if (viewer?.onBackPressed() == false) return
else super.onBackPressed() else super.onBackPressed()
} }
@ -202,39 +193,35 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.image -> {
uploadImage()
true
}
R.id.create -> { R.id.create -> {
loadEditor() loadEditor()
true true
} }
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) saveAuthorName(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
@ -244,36 +231,44 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD
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
} }
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()
@ -282,11 +277,13 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD
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
addBookmark(currentUrl.split("/").last(), input.toString()) ?: "", allowEmpty = false) { _, input ->
}) val curPage = currentPage
if (curPage?.url != null) addBookmark(curPage.url.split("/").last(), input.toString())
}
.show() .show()
true true
} }
@ -294,25 +291,28 @@ class MainActivity : AppCompatActivity(), AdvancedWebView.Listener, FileChooserD
val shareIntent = Intent() val shareIntent = Intent()
shareIntent.action = Intent.ACTION_SEND shareIntent.action = Intent.ACTION_SEND
shareIntent.type = "text/plain" shareIntent.type = "text/plain"
shareIntent.putExtra(Intent.EXTRA_TITLE, webView?.title) shareIntent.putExtra(Intent.EXTRA_TITLE, currentPage?.title)
shareIntent.putExtra(Intent.EXTRA_TEXT, currentUrl) shareIntent.putExtra(Intent.EXTRA_TEXT, currentPage?.url)
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) true
.positiveText(android.R.string.ok) }
R.id.login -> {
MaterialDialog(this@MainActivity)
.title(R.string.login)
.message(R.string.login_desc)
.positiveButton(android.R.string.ok)
.positiveButton {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/telegraph")))
}
.show() .show()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
} }

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"
@ -29,14 +29,14 @@ fun Context.saveBookmarks(bookmarks: List<Pair<String, String>>) {
).apply() ).apply()
} }
fun Context.accessToken(): String = PreferenceManager.getDefaultSharedPreferences(this).getString("accessToken", "") var Context.accessToken: String
get() = PreferenceManager.getDefaultSharedPreferences(this).getString("accessToken", "") as String
set(value) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putString("accessToken", value).apply()
}
fun Context.saveAccessToken(token: String) { var Context.authorName: String?
PreferenceManager.getDefaultSharedPreferences(this).edit().putString("accessToken", token).apply() get() = PreferenceManager.getDefaultSharedPreferences(this).getString("authorName", null)
} set(value) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putString("authorName", value).apply()
fun Context.authorName(): String? = PreferenceManager.getDefaultSharedPreferences(this).getString("authorName", null) }
fun Context.saveAuthorName(name: String) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putString("authorName", name).apply()
}

View File

@ -1,30 +1,41 @@
package telegra.ph package telegra.ph
import com.github.kittinunf.fuel.android.core.Json import com.github.kittinunf.fuel.core.FuelError
import com.github.kittinunf.fuel.android.extension.responseJson import com.github.kittinunf.fuel.core.FuelManager
import com.github.kittinunf.fuel.core.* import com.github.kittinunf.fuel.core.Request
import com.github.kittinunf.fuel.core.Response
import com.github.kittinunf.fuel.core.interceptors.redirectResponseInterceptor
import com.github.kittinunf.fuel.httpPost import com.github.kittinunf.fuel.httpPost
import com.github.kittinunf.fuel.httpUpload 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
import java.io.File import java.net.HttpCookie
import java.net.URLConnection
object TelegraphApi { object TelegraphApi {
// Telegraph private var loginAccessToken: String? = null
init { init {
FuelManager.instance.basePath = "https://api.telegra.ph" FuelManager.instance.basePath = "https://api.telegra.ph"
FuelManager.instance.removeAllResponseInterceptors()
FuelManager.instance.addResponseInterceptor {
telegraphLoginInterceptor()
}
// Fix login
FuelManager.instance.addResponseInterceptor {
redirectResponseInterceptor(FuelManager.instance)
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) {
@ -102,7 +113,7 @@ object TelegraphApi {
val url: String = json.optString("url") val url: String = json.optString("url")
val title: String = json.optString("title") val title: String = json.optString("title")
val description: String = json.optString("description") val description: String = json.optString("description")
val authorName: String? = json.optString("authorName") val authorName: String? = json.optString("author_name")
val authorUrl: String? = json.optString("author_url") val authorUrl: String? = json.optString("author_url")
val imageUrl: String? = json.optString("image_url") val imageUrl: String? = json.optString("image_url")
val content: String? = json.optJSONArray("content")?.parseContent() val content: String? = json.optJSONArray("content")?.parseContent()
@ -126,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
} }
@ -137,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()
@ -151,25 +165,27 @@ object TelegraphApi {
} }
} }
fun uploadImage(file: File, callback: (success: Boolean, src: String?, error: String?) -> Unit) { // Dirty hacks
"http://telegra.ph/upload".httpUpload()
.dataParts { _, _ -> fun login(authUrl: String, callback: (success: Boolean, accessToken: String?, account: Account?) -> Unit) {
listOf(DataPart(file, name = "FileUpload", type = URLConnection.guessContentTypeFromName(file.name))) loginAccessToken = null
} authUrl.httpPost().response { _, _, _ ->
.responseJson { _, _, result -> if (loginAccessToken != null) getAccountInfo(accessToken = loginAccessToken!!) { success, account, _ ->
val (json, error) = result if (success) callback(true, loginAccessToken, account)
if (error == null && json != null) { else callback(false, null, null)
val jsonObj = json.array().optJSONObject(0) } else callback(false, null, null)
val src = jsonObj?.optString("src") }
if (src != null) {
callback(true, src, null)
} else {
callback(false, null, null)
}
} else {
callback(false, null, error?.message)
}
}
} }
private fun telegraphLoginInterceptor(): (Request, Response) -> Response =
{ _, response ->
response.headers["Set-Cookie"]
.flatMap { HttpCookie.parse(it) }
.find { it.name == "tph_token" }
?.let {
loginAccessToken = it.value
}
response
}
} }

View File

@ -0,0 +1,57 @@
package telegra.ph
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.webkit.JavascriptInterface
import im.delight.android.webview.AdvancedWebView
class Viewer @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AdvancedWebView(context, attrs, defStyleAttr) {
init {
prepare()
}
@SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface")
fun prepare() {
settings.javaScriptEnabled = true
settings.loadWithOverviewMode = true
settings.useWideViewPort = true
overScrollMode = View.OVER_SCROLL_NEVER
setMixedContentAllowed(true)
loadDataWithBaseURL("https://telegra.ph", context.assets.open("viewer.html").bufferedReader().readText(), "text/html", "utf-8", null)
}
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');")
}
private fun setAuthor(author: String?, url: String?) {
this.loadUrl("javascript:setAuthor('$author','$url');")
}
private fun setViews(views: Int) {
this.loadUrl("javascript:setViews('$views');")
}
private fun setDescription(description: String) {
this.loadUrl("javascript:setDescription('${description.replace("\n", "<br>")}');")
}
private fun setContent(content: String?) {
this.loadUrl("javascript:setContent('${content?.replace("'", "\\'")}');")
}
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
@ -8,14 +7,10 @@
<telegra.ph.Editor <telegra.ph.Editor
android:id="@+id/editor" android:id="@+id/editor"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent" />
<im.delight.android.webview.AdvancedWebView <telegra.ph.Viewer
android:id="@+id/webView" android:id="@+id/viewer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent" />
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"/>
</LinearLayout> </LinearLayout>

View File

@ -1,44 +1,48 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/image"
android:title="@string/add_image"
app:showAsAction="ifRoom" />
<item <item
android:id="@+id/create" android:id="@+id/create"
android:title="@string/create" android:title="@string/create"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/publish" android:id="@+id/publish"
android:title="@string/publish" android:title="@string/publish"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/edit" android:id="@+id/edit"
android:title="@string/edit" android:title="@string/edit"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/try_edit" android:id="@+id/try_edit"
android:title="@string/try_edit" android:title="@string/try_edit"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/bookmark" android:id="@+id/bookmark"
android:title="@string/bookmark_this" android:title="@string/bookmark_this"
app:showAsAction="ifRoom"/> app:showAsAction="never" />
<item <item
android:id="@+id/bookmarks" android:id="@+id/bookmarks"
android:title="@string/bookmarks" android:title="@string/bookmarks"
app:showAsAction="ifRoom"/> 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"
app:showAsAction="ifRoom"/> app:showAsAction="never" />
<item <item
android:id="@+id/share" android:id="@+id/share"
android:title="@string/share" android:title="@string/share"
app:showAsAction="ifRoom"/> app:showAsAction="never" />
<item <item
android:id="@+id/help" android:id="@+id/login"
android:title="@string/help" android:title="@string/login"
app:showAsAction="ifRoom"/> app:showAsAction="never" />
<item
android:id="@+id/about"
android:title="@string/about"
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">#3F51B5</color> <color name="primaryColor">#fafafa</color>
<color name="colorPrimaryDark">#303F9F</color> <color name="primaryDarkColor">#c7c7c7</color>
<color name="colorAccent">#FF4081</color> <color name="primaryTextColor">#000000</color>
</resources> </resources>

View File

@ -1,29 +1,29 @@
<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>Why can\'t I select headings?</h3>Unfortunately I wasn\'t able to add the feature yet, but you can do it manually via the code editor.<h3>Why can\'t I login with my Telegram account?</h3>That\'s not possible!<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>, <a href=\"https://github.com/googlesamples/easypermissions\">EasyPermissions</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="create">Create</string> <string name="delete_bookmark">Delete Bookmark</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>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="delete_question">Do you really want to delete this?</string> <string name="delete_question">Do you really want to delete this?</string>
<string name="publish">Publish</string> <string name="publish">Publish</string>
<string name="edit">Edit (safe)</string> <string name="edit">Edit</string>
<string name="try_edit">Edit (unsafe)</string> <string name="try_edit">Try to edit</string>
<string name="error">Error</string> <string name="error">Error</string>
<string name="error_desc">Something unexpected happened!</string> <string name="error_desc">Something unexpected happened!</string>
<string name="viewer_html_head">
<![CDATA[<!DOCTYPE html><html><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/3.3.7/css/bootstrap.min.css\"><style> * { max-width: 100%; height: auto; word-break: break-all; word-break: break-word; }</style><script src=\"http://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js\"></script><script src=\"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js\"></script></head><body>]]>
</string>
<string name="viewer_html_end">
<![CDATA[</body></html>]]>
</string>
<string name="published">Published posts</string> <string name="published">Published posts</string>
<string name="name_question">Your name?</string> <string name="name_question">Your name?</string>
<string name="name_hint">Awesome Writer</string> <string name="name_hint">Awesome Writer</string>
<string name="add_image">Add image</string> <string name="login_failed">Login failed. Try again!</string>
<string name="success">Success</string>
<string name="login_success">You successfully logged in!</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="open">Open</string>
</resources> </resources>

View File

@ -1,10 +1,10 @@
<resources> <resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <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