From 1d92436a3c76a28c0241a4fd305b59ea1607b535 Mon Sep 17 00:00:00 2001 From: Peter Stuifzand Date: Thu, 22 Mar 2018 21:54:28 +0100 Subject: [PATCH] Add likes and better authentication --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 29 ++- .../java/eu/stuifzand/micropub/AuthError.java | 5 + .../eu/stuifzand/micropub/LikeActivity.java | 180 ++++++++++++++++++ .../eu/stuifzand/micropub/MainActivity.java | 66 ++++++- .../stuifzand/micropub/OnTokenAcquired.java | 9 +- .../eu/stuifzand/micropub/PostViewModel.java | 31 +++ .../micropub/auth/AuthenticationActivity.java | 16 +- .../micropub/auth/Authenticator.java | 2 +- .../auth/VerifyAuthenticationTask.java | 5 +- .../micropub/auth/WebsigninTask.java | 16 +- .../eu/stuifzand/micropub/client/Post.java | 30 ++- .../stuifzand/micropub/client/PostTask.java | 17 +- .../stuifzand/micropub/client/Response.java | 6 +- app/src/main/res/layout/activity_like.xml | 46 +++++ app/src/main/res/layout/activity_main.xml | 1 + app/src/main/res/layout/content_main.xml | 70 +++---- app/src/main/res/menu/menu_like.xml | 14 ++ app/src/main/res/menu/menu_main.xml | 19 +- .../res/mipmap-xxhdpi/ic_image_black_48dp.png | Bin 0 -> 807 bytes .../res/mipmap-xxhdpi/ic_send_black_48dp.png | Bin 0 -> 714 bytes app/src/main/res/values/strings.xml | 6 + 22 files changed, 497 insertions(+), 75 deletions(-) create mode 100644 app/src/main/java/eu/stuifzand/micropub/AuthError.java create mode 100644 app/src/main/java/eu/stuifzand/micropub/LikeActivity.java create mode 100644 app/src/main/res/layout/activity_like.xml create mode 100644 app/src/main/res/menu/menu_like.xml create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_image_black_48dp.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_send_black_48dp.png diff --git a/app/build.gradle b/app/build.gradle index 4c3bbfb..064b41f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "eu.stuifzand.micropub" minSdkVersion 15 targetSdkVersion 26 - versionCode 5 - versionName '0.0.5-alpha' + versionCode 7 + versionName '0.0.7-alpha' testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5b7b425..482f626 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,6 @@ android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="22" /> - @@ -34,12 +33,18 @@ - - - - - + + + + + + + + + + + @@ -56,9 +61,17 @@ + android:resource="@xml/authenticator" /> + + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/java/eu/stuifzand/micropub/AuthError.java b/app/src/main/java/eu/stuifzand/micropub/AuthError.java new file mode 100644 index 0000000..0bd56db --- /dev/null +++ b/app/src/main/java/eu/stuifzand/micropub/AuthError.java @@ -0,0 +1,5 @@ +package eu.stuifzand.micropub; + +interface AuthError { + void handleErrorMessage(String msg); +} diff --git a/app/src/main/java/eu/stuifzand/micropub/LikeActivity.java b/app/src/main/java/eu/stuifzand/micropub/LikeActivity.java new file mode 100644 index 0000000..bba05f6 --- /dev/null +++ b/app/src/main/java/eu/stuifzand/micropub/LikeActivity.java @@ -0,0 +1,180 @@ +package eu.stuifzand.micropub; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.net.Uri; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import eu.stuifzand.micropub.client.Client; +import eu.stuifzand.micropub.client.Post; +import eu.stuifzand.micropub.databinding.ActivityLikeBinding; +import okhttp3.HttpUrl; + +public class LikeActivity extends AppCompatActivity { + + private AccountManager accountManager; + + private Account selectedAccount; + private String authToken; + private Client client; + private PostViewModel postModel; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + accountManager = AccountManager.get(this); + + AccountManager am = AccountManager.get(this); + Bundle options = new Bundle(); + + postModel = ViewModelProviders.of(LikeActivity.this).get(PostViewModel.class); + client = ViewModelProviders.of(LikeActivity.this).get(Client.class); + + TokenReady callback = (accountType, accountName, token) -> { + Account[] accounts = accountManager.getAccountsByType(accountType); + if (accounts.length == 0) + return; + selectedAccount = accounts[0]; + authToken = token; + + String micropubBackend = accountManager.getUserData(selectedAccount, "micropub"); + if (micropubBackend == null) return; + + client.setToken(accountType, accountName, token); + client.loadConfig(HttpUrl.parse(micropubBackend)); + + final View coordinator = findViewById(R.id.coordinator); + + client.getResponse().observe(LikeActivity.this, response -> { + Log.i("micropub", "response received " + response.isSuccess()); + if (response.isSuccess()) { + postModel.clear(); + Snackbar.make(coordinator, R.string.post_successful, Snackbar.LENGTH_LONG) + .setAction("Open", v -> { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(response.getUrl())); + startActivity(browserIntent); + }) + .show(); + } else { + Snackbar.make(coordinator, R.string.post_failed, Snackbar.LENGTH_SHORT).show(); + } + }); + + client.getMediaResponse().observe(LikeActivity.this, response -> { + Log.i("micropub", "media response received " + response.isSuccess()); + if (response.isSuccess()) { + postModel.setPhoto(response.getUrl()); + Toast.makeText(LikeActivity.this, "Photo upload succesful, photo url filled", Toast.LENGTH_SHORT).show(); + } + }); + }; + + AuthError onError = (msg) -> { + LikeActivity.this.runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(LikeActivity.this, msg, Toast.LENGTH_LONG).show(); + } + }); + }; + accountManager.getAuthTokenByFeatures( + "Indieauth", + "token", + null, + this, + options, + null, + new OnTokenAcquired(this, callback, onError), + null + ); + +// setContentView(R.layout.activity_main); + ActivityLikeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_like); + + binding.setViewModel(postModel); + binding.setClient(client); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + + Intent intent = getIntent(); + Log.i("micropub", intent.toString()); + if (intent != null) { + String urlOrNote = intent.getStringExtra(Intent.EXTRA_TEXT); + if (urlOrNote != null) { + HttpUrl url = HttpUrl.parse(urlOrNote); + if (url != null) { + postModel.likeOf.set(urlOrNote); + } else { + postModel.findLikeOf(urlOrNote); + } + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_like, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_send) { + InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE); + if (this.getCurrentFocus() != null && inputManager != null) { + inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0); + inputManager.hideSoftInputFromInputMethod(this.getCurrentFocus().getWindowToken(), 0); + } + sendPost(null); + } + return super.onOptionsItemSelected(item); + } + + public void sendPost(View view) { + AccountManager am = AccountManager.get(this); + Bundle options = new Bundle(); + + TokenReady callback = (accountType, accountName, token) -> { + String micropubBackend = accountManager.getUserData(selectedAccount, "micropub"); + if (micropubBackend == null) { + Log.i("micropub", "micropub backend == null"); + return; + } + Log.i("micropub", "Sending message to " + micropubBackend); + Post post = postModel.getPost(); + client.createPost(post, token, HttpUrl.parse(micropubBackend)); + }; + AuthError onError = (msg) -> { + LikeActivity.this.runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(LikeActivity.this, msg, Toast.LENGTH_LONG).show(); + } + }); + }; + + accountManager.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(this, callback, onError), null); + } +} diff --git a/app/src/main/java/eu/stuifzand/micropub/MainActivity.java b/app/src/main/java/eu/stuifzand/micropub/MainActivity.java index 8e2e7d5..a1088b4 100644 --- a/app/src/main/java/eu/stuifzand/micropub/MainActivity.java +++ b/app/src/main/java/eu/stuifzand/micropub/MainActivity.java @@ -3,10 +3,17 @@ package eu.stuifzand.micropub; import android.accounts.Account; import android.accounts.AccountManager; import android.app.Activity; +import android.app.Notification; import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; import android.content.Intent; import android.databinding.DataBindingUtil; +import android.media.session.MediaSession; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; @@ -14,6 +21,8 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; import java.io.FileNotFoundException; import java.io.IOException; @@ -60,10 +69,20 @@ public class MainActivity extends AppCompatActivity { client.setToken(accountType, accountName, token); client.loadConfig(HttpUrl.parse(micropubBackend)); + final View coordinator = findViewById(R.id.coordinator); + client.getResponse().observe(MainActivity.this, response -> { Log.i("micropub", "response received " + response.isSuccess()); if (response.isSuccess()) { postModel.clear(); + Snackbar.make(coordinator, R.string.post_successful, Snackbar.LENGTH_LONG) + .setAction("Open", v -> { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(response.getUrl())); + startActivity(browserIntent); + }) + .show(); + } else { + Snackbar.make(coordinator, R.string.post_failed, Snackbar.LENGTH_SHORT).show(); } }); @@ -71,10 +90,28 @@ public class MainActivity extends AppCompatActivity { Log.i("micropub", "media response received " + response.isSuccess()); if (response.isSuccess()) { postModel.setPhoto(response.getUrl()); + Toast.makeText(MainActivity.this, "Photo upload succesful, photo url filled", Toast.LENGTH_SHORT).show(); } }); }; - accountManager.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(this, callback), null); + + AuthError onError = (msg) -> { + MainActivity.this.runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show(); + } + }); + }; + accountManager.getAuthTokenByFeatures( + "Indieauth", + "token", + null, + this, + options, + null, + new OnTokenAcquired(this, callback, onError), + null + ); // setContentView(R.layout.activity_main); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); @@ -93,7 +130,7 @@ public class MainActivity extends AppCompatActivity { if (url != null) { postModel.inReplyTo.set(urlOrNote); } else { - postModel.content.set(urlOrNote); + postModel.findReplyTo(urlOrNote); } } } @@ -124,9 +161,23 @@ public class MainActivity extends AppCompatActivity { //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { + // TODO: implement some settings return true; } if (id == R.id.action_send) { + InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE); + if (this.getCurrentFocus() != null && inputManager != null) { + inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0); + inputManager.hideSoftInputFromInputMethod(this.getCurrentFocus().getWindowToken(), 0); + } + sendPost(null); + } else if (id == R.id.action_photo) { + InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE); + if (this.getCurrentFocus() != null && inputManager != null) { + inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0); + inputManager.hideSoftInputFromInputMethod(this.getCurrentFocus().getWindowToken(), 0); + } + galleryIntent(null); } return super.onOptionsItemSelected(item); @@ -146,8 +197,15 @@ public class MainActivity extends AppCompatActivity { Post post = postModel.getPost(); client.createPost(post, token, HttpUrl.parse(micropubBackend)); }; + AuthError onError = (msg) -> { + MainActivity.this.runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show(); + } + }); + }; - accountManager.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(this, callback), null); + accountManager.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(this, callback, onError), null); } public void galleryIntent(View view) { @@ -179,8 +237,10 @@ public class MainActivity extends AppCompatActivity { client.postMedia(output, mimeType); } catch (FileNotFoundException e) { + Toast.makeText(this, "File not found: " + e.getMessage(), Toast.LENGTH_SHORT).show(); Log.e("micropub", "Error while copying image", e); } catch (IOException e) { + Toast.makeText(this, "Problem with IO " + e.getMessage(), Toast.LENGTH_SHORT).show(); Log.e("micropub", "Error while copying image", e); } } diff --git a/app/src/main/java/eu/stuifzand/micropub/OnTokenAcquired.java b/app/src/main/java/eu/stuifzand/micropub/OnTokenAcquired.java index 7bc69a0..265d28c 100644 --- a/app/src/main/java/eu/stuifzand/micropub/OnTokenAcquired.java +++ b/app/src/main/java/eu/stuifzand/micropub/OnTokenAcquired.java @@ -7,18 +7,22 @@ import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.app.Activity; import android.content.Intent; +import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; +import android.widget.Toast; import java.io.IOException; public class OnTokenAcquired implements AccountManagerCallback { private final TokenReady callback; + private AuthError error; private Activity activity; - public OnTokenAcquired(Activity activity, TokenReady callback) { + public OnTokenAcquired(Activity activity, TokenReady callback, AuthError error) { this.activity = activity; this.callback = callback; + this.error = error; } @Override @@ -39,10 +43,13 @@ public class OnTokenAcquired implements AccountManagerCallback { callback.tokenReady(bundle.getString("accountType"), bundle.getString("authAccount"), token); } catch (OperationCanceledException e) { Log.e("micropub", "on token acquired", e); + error.handleErrorMessage(e.getMessage()); } catch (IOException e) { Log.e("micropub", "on token acquired", e); + error.handleErrorMessage(e.getMessage()); } catch (AuthenticatorException e) { Log.e("micropub", "on token acquired", e); + error.handleErrorMessage(e.getMessage()); } } } diff --git a/app/src/main/java/eu/stuifzand/micropub/PostViewModel.java b/app/src/main/java/eu/stuifzand/micropub/PostViewModel.java index d932993..86e065d 100644 --- a/app/src/main/java/eu/stuifzand/micropub/PostViewModel.java +++ b/app/src/main/java/eu/stuifzand/micropub/PostViewModel.java @@ -6,6 +6,8 @@ import android.databinding.ObservableField; import android.databinding.ObservableList; import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import eu.stuifzand.micropub.client.Client; import eu.stuifzand.micropub.client.Post; @@ -13,11 +15,18 @@ import eu.stuifzand.micropub.client.Syndication; import okhttp3.HttpUrl; public class PostViewModel extends ViewModel { + private static final Pattern urlPattern = Pattern.compile( + "(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)" + + "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*" + + "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)", + Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + public final ObservableField name = new ObservableField<>(); public final ObservableField content = new ObservableField<>(); public final ObservableField category = new ObservableField<>(); public final ObservableField inReplyTo = new ObservableField<>(); public final ObservableField photo = new ObservableField<>(); + public final ObservableField likeOf = new ObservableField<>(); public PostViewModel() { this.name.set(""); @@ -25,6 +34,7 @@ public class PostViewModel extends ViewModel { this.category.set(""); this.inReplyTo.set(""); this.photo.set(""); + this.likeOf.set(""); } public void clear() { @@ -33,6 +43,26 @@ public class PostViewModel extends ViewModel { this.category.set(""); this.inReplyTo.set(""); this.photo.set(""); + this.likeOf.set(""); + } + + public void findReplyTo(String urlOrNote) { + Matcher matcher = urlPattern.matcher(urlOrNote); + if (matcher.find()) { + String url = matcher.group(1); + inReplyTo.set(url); + String s = urlOrNote.replaceFirst(urlPattern.pattern(), ""); + this.content.set(s); + } else { + this.content.set(urlOrNote); + } + } + + public void findLikeOf(String urlOrNote) { + Matcher matcher = urlPattern.matcher(urlOrNote); + if (matcher.find()) { + likeOf.set(matcher.group(1)); + } } public void setPhoto(String url) { @@ -44,6 +74,7 @@ public class PostViewModel extends ViewModel { if (!this.photo.get().equals("")) { post.setPhoto(this.photo.get()); } + post.setLikeOf(HttpUrl.parse(likeOf.get())); return post; } } diff --git a/app/src/main/java/eu/stuifzand/micropub/auth/AuthenticationActivity.java b/app/src/main/java/eu/stuifzand/micropub/auth/AuthenticationActivity.java index f3a6978..bdc301a 100644 --- a/app/src/main/java/eu/stuifzand/micropub/auth/AuthenticationActivity.java +++ b/app/src/main/java/eu/stuifzand/micropub/auth/AuthenticationActivity.java @@ -5,6 +5,7 @@ import android.accounts.AccountAuthenticatorActivity; import android.accounts.AccountAuthenticatorResponse; import android.accounts.AccountManager; import android.content.Intent; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.RequiresApi; @@ -15,6 +16,8 @@ import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; +import java.net.URI; + import eu.stuifzand.micropub.R; import okhttp3.HttpUrl; @@ -37,7 +40,6 @@ public class AuthenticationActivity extends AccountAuthenticatorActivity { final String me = intent.getStringExtra(WebsigninTask.ME); final AccountAuthenticatorResponse response = intent.getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE); - WebView webview = findViewById(R.id.webview); WebSettings webSettings = webview.getSettings(); webSettings.setJavaScriptEnabled(true); @@ -46,7 +48,7 @@ public class AuthenticationActivity extends AccountAuthenticatorActivity { HttpUrl.Builder builder = HttpUrl.parse(endpoint).newBuilder(); builder.setQueryParameter("me", me) .setQueryParameter("client_id", "https://stuifzand.eu/micropub") - .setQueryParameter("redirect_uri", "https://stuifzand.eu/micropub-auth") + .setQueryParameter("redirect_uri", "wrimini://oauth") .setQueryParameter("response_type", "code") .setQueryParameter("state", "1234") // @TODO use random states, check the state later .setQueryParameter("scope", "create edit update post delete"); // @TODO use different scope @@ -56,7 +58,7 @@ public class AuthenticationActivity extends AccountAuthenticatorActivity { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { - Log.i("micropub", request.getMethod()+ " "+request.getUrl()); + Log.i("micropub", request.getMethod() + " " + request.getUrl()); Log.i("micropub", error.toString()); } @@ -64,10 +66,10 @@ public class AuthenticationActivity extends AccountAuthenticatorActivity { public boolean shouldOverrideUrlLoading(WebView viewx, WebResourceRequest request) { Log.i("micropub", "New API: " + request.getUrl().toString()); String url = request.getUrl().toString(); - if (url.startsWith("https://stuifzand.eu/micropub-auth")) { - HttpUrl httpUrl = HttpUrl.parse(url); - String code = httpUrl.queryParameter("code"); - String state = httpUrl.queryParameter("state"); + if (url.startsWith("wrimini://oauth")) { + Uri uri = Uri.parse(url); + String code = uri.getQueryParameter("code"); + //String state = httpUrl.queryParameter("state"); new VerifyAuthenticationTask(response, AuthenticationActivity.this).execute(endpoint, me, code); diff --git a/app/src/main/java/eu/stuifzand/micropub/auth/Authenticator.java b/app/src/main/java/eu/stuifzand/micropub/auth/Authenticator.java index 1d2d17b..ca00861 100644 --- a/app/src/main/java/eu/stuifzand/micropub/auth/Authenticator.java +++ b/app/src/main/java/eu/stuifzand/micropub/auth/Authenticator.java @@ -75,7 +75,7 @@ public class Authenticator extends AbstractAccountAuthenticator { if (TextUtils.isEmpty(authToken)) { RequestBody formBody = new FormBody.Builder() .add("code", am.getPassword(account)) - .add("redirect_uri", "https://stuifzand.eu/micropub-auth") + .add("redirect_uri", "wrimini://oauth") .add("client_id", "https://stuifzand.eu/micropub") .add("me", account.name) .add("grant_type", "authorization_code") diff --git a/app/src/main/java/eu/stuifzand/micropub/auth/VerifyAuthenticationTask.java b/app/src/main/java/eu/stuifzand/micropub/auth/VerifyAuthenticationTask.java index 0c62c57..2cac900 100644 --- a/app/src/main/java/eu/stuifzand/micropub/auth/VerifyAuthenticationTask.java +++ b/app/src/main/java/eu/stuifzand/micropub/auth/VerifyAuthenticationTask.java @@ -1,5 +1,6 @@ package eu.stuifzand.micropub.auth; +import android.accounts.Account; import android.accounts.AccountAuthenticatorResponse; import android.accounts.AccountManager; import android.content.Intent; @@ -70,7 +71,7 @@ public class VerifyAuthenticationTask extends AsyncTask { String profileUrl = strings[0]; bundle.putString(ME, profileUrl); Connection conn = Jsoup.connect(profileUrl); + conn.timeout(10*1000); Document doc = conn.get(); Connection.Response resp = conn.response(); @@ -81,7 +83,8 @@ public class WebsigninTask extends AsyncTask { linkHeaders.put(rel, link.attr("href")); } } - } catch (IOException e) { + } catch (Exception e) { + bundle.putString("ERROR", e.getMessage()); return bundle; } @@ -93,12 +96,23 @@ public class WebsigninTask extends AsyncTask { } } + for (String rel : rels) { + if (bundle.getString(rel) == null) { + bundle.putString("ERROR", "Missing header or link: " + rel); + break; + } + } Log.i("micropub", bundle.toString()); return bundle; } @Override protected void onPostExecute(Bundle bundle) { + String error = bundle.getString("ERROR"); + if (error != null && error.length() > 0) { + Toast.makeText(this.activity, error, Toast.LENGTH_SHORT).show(); + return; + } Intent intent = new Intent(this.activity, AuthenticationActivity.class); intent.putExtras(activity.getIntent()); intent.putExtras(bundle); diff --git a/app/src/main/java/eu/stuifzand/micropub/client/Post.java b/app/src/main/java/eu/stuifzand/micropub/client/Post.java index f3c4cbd..6bbb6d7 100644 --- a/app/src/main/java/eu/stuifzand/micropub/client/Post.java +++ b/app/src/main/java/eu/stuifzand/micropub/client/Post.java @@ -9,23 +9,27 @@ public class Post { private String[] categories; private String[] syndicationUids; private String photo; + private HttpUrl likeOf; public Post(String content) { - this.content = content; + if (content.equals("")) { + this.content=null; + } else { + this.content = content; + } this.categories = new String[]{}; this.syndicationUids = new String[]{}; } public Post(String name, String content) { - this.name = name; - this.content = content; + this(content); this.categories = new String[]{}; + this.name = name; this.syndicationUids = new String[]{}; } public Post(String name, String content, String categories) { - this.name = name; - this.content = content; + this(name, content); this.categories = categories.split("\\s+"); if (this.categories.length == 1 && this.categories[0].length() == 0) { this.categories = new String[]{}; @@ -82,4 +86,20 @@ public class Post { public boolean hasPhoto() { return this.photo != null; } + + public boolean hasLikeOf() { + return this.likeOf != null; + } + + public void setLikeOf(HttpUrl likeOf) { + this.likeOf = likeOf; + } + + public String getLikeOf() { + return likeOf.toString(); + } + + public boolean hasContent() { + return content != null; + } } diff --git a/app/src/main/java/eu/stuifzand/micropub/client/PostTask.java b/app/src/main/java/eu/stuifzand/micropub/client/PostTask.java index 63c1214..abe0054 100644 --- a/app/src/main/java/eu/stuifzand/micropub/client/PostTask.java +++ b/app/src/main/java/eu/stuifzand/micropub/client/PostTask.java @@ -31,9 +31,11 @@ class PostTask extends AsyncTask { @Override protected Void doInBackground(String... strings) { FormBody.Builder builder = new FormBody.Builder(); - builder.add("h", "entry") - .add("content", post.getContent()); + builder.add("h", "entry"); + if (post.hasContent()) { + builder.add("content", post.getContent()); + } for (String cat : post.getCategories()) { builder.add("category[]", cat); } @@ -54,6 +56,10 @@ class PostTask extends AsyncTask { builder.add("photo", post.getPhoto()); } + if (post.hasLikeOf()) { + builder.add("like-of", post.getLikeOf()); + } + RequestBody formBody = builder.build(); Request request = new Request.Builder() @@ -76,15 +82,16 @@ class PostTask extends AsyncTask { okhttp3.Response httpResponse = null; try { httpResponse = call.execute(); - if (httpResponse.code() == 201) { + int code = httpResponse.code(); + if (code == 201) { String location = httpResponse.header("Location"); response.postValue(Response.successful(location)); } else { - response.postValue(Response.failed()); + response.postValue(Response.failed(httpResponse.toString())); } } catch (IOException e) { - response.postValue(Response.failed()); + response.postValue(Response.failed(e.getMessage())); } finally { if (httpResponse != null) { httpResponse.close(); diff --git a/app/src/main/java/eu/stuifzand/micropub/client/Response.java b/app/src/main/java/eu/stuifzand/micropub/client/Response.java index c20eef1..0c98c70 100644 --- a/app/src/main/java/eu/stuifzand/micropub/client/Response.java +++ b/app/src/main/java/eu/stuifzand/micropub/client/Response.java @@ -13,8 +13,8 @@ public class Response { this.url = url; } - public static Response failed() { - return new Response(false); + public static Response failed(String why) { + return new Response(false, why); } public static Response successful(String url) { @@ -24,8 +24,8 @@ public class Response { public boolean isSuccess() { return success; } - public String getUrl() { return url; } + public String getWhy() { return url; } } diff --git a/app/src/main/res/layout/activity_like.xml b/app/src/main/res/layout/activity_like.xml new file mode 100644 index 0000000..a9545c9 --- /dev/null +++ b/app/src/main/res/layout/activity_like.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c589395..35c2019 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -14,6 +14,7 @@ diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index d2cb150..f87cec4 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools"> - @@ -14,19 +13,23 @@ type="eu.stuifzand.micropub.client.Client" /> - + android:scrollbars="vertical"> + + + + + + + app:layout_constraintTop_toBottomOf="@+id/editNameLayout"> -