Cleanup overal

This commit is contained in:
Peter Stuifzand 2018-03-04 17:08:36 +01:00
parent 28576f6846
commit c685f0a944
15 changed files with 573 additions and 252 deletions

View File

@ -2,11 +2,7 @@ package eu.stuifzand.micropub;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Application;
import android.app.Activity;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.databinding.DataBindingUtil;
@ -19,26 +15,71 @@ import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.InputStream;
import eu.stuifzand.micropub.databinding.ActivityMainBinding;
import eu.stuifzand.micropub.client.Client;
import eu.stuifzand.micropub.client.Post;
import eu.stuifzand.micropub.client.Syndication;
import okhttp3.HttpUrl;
import static eu.stuifzand.micropub.utils.IOUtils.getBytes;
public class MainActivity extends AppCompatActivity {
private static final int SELECT_FILE = 12;
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(MainActivity.this).get(PostViewModel.class);
client = ViewModelProviders.of(MainActivity.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));
client.getResponse().observe(MainActivity.this, response -> {
Log.i("micropub", "response received " + response.isSuccess());
if (response.isSuccess()) {
postModel.clear();
}
});
client.getMediaResponse().observe(MainActivity.this, response -> {
Log.i("micropub", "media response received " + response.isSuccess());
if (response.isSuccess()) {
postModel.setPhoto(response.getUrl());
}
});
};
accountManager.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(this, callback), null);
// setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
PostViewModel model = ViewModelProviders.of(MainActivity.this).get(PostViewModel.class);
Client client = ViewModelProviders.of(MainActivity.this).get(Client.class);
binding.setViewModel(model);
binding.setViewModel(postModel);
binding.setClient(client);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
@ -50,9 +91,9 @@ public class MainActivity extends AppCompatActivity {
if (urlOrNote != null) {
HttpUrl url = HttpUrl.parse(urlOrNote);
if (url != null) {
model.inReplyTo.set(urlOrNote);
postModel.inReplyTo.set(urlOrNote);
} else {
model.content.set(urlOrNote);
postModel.content.set(urlOrNote);
}
}
}
@ -65,16 +106,6 @@ public class MainActivity extends AppCompatActivity {
// .setAction("Action", null).show();
// }
// });
TokenReady callback = (accountType, accountName, token) -> {
Log.i("micropub", "TokenReady called " + accountType + " " + accountName + " " + token);
client.setToken(accountType, accountName, token);
client.loadSyndicates();
};
AccountManager am = AccountManager.get(this);
Bundle options = new Bundle();
am.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(callback), null);
}
@Override
@ -104,76 +135,54 @@ public class MainActivity extends AppCompatActivity {
public void sendPost(View view) {
AccountManager am = AccountManager.get(this);
Bundle options = new Bundle();
TokenReady callback = new TokenReady() {
@Override
public void tokenReady(String accountType, String accountName, String token) {
PostViewModel model = ViewModelProviders.of(MainActivity.this).get(PostViewModel.class);
AccountManager am = AccountManager.get(MainActivity.this);
Account[] accounts = am.getAccountsByType(accountType);
String micropubBackend = null;
for (Account account : accounts) {
if (account.name.equals(accountName)) {
micropubBackend = am.getUserData(account, "micropub");
}
}
if (micropubBackend != null) {
Log.i("micropub", "Sending message to " + micropubBackend);
Client client = ViewModelProviders.of(MainActivity.this).get(Client.class);
client.getResponse().observe(MainActivity.this, response -> {
Log.i("micropub", "response received " + response.isSuccess());
if (response.isSuccess()) {
model.clear();
}
});
Post post = new Post(null, model.content.get(), model.category.get(), HttpUrl.parse(model.inReplyTo.get()));
List<String> uids = new ArrayList<String>();
for (Syndication s : client.syndicates) {
if (s.checked.get()) {
uids.add(s.uid.get());
}
}
post.setSyndicationUids(uids.toArray(new String[uids.size()]));
client.createPost(post, token, HttpUrl.parse(micropubBackend));
}
}
};
am.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(callback), null);
}
public class OnTokenAcquired implements AccountManagerCallback<Bundle> {
private final TokenReady callback;
public OnTokenAcquired(TokenReady callback) {
this.callback = callback;
}
@Override
public void run(AccountManagerFuture<Bundle> result) {
// Get the result of the operation from the AccountManagerFuture.
try {
Bundle bundle = result.getResult();
Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (launch != null) {
MainActivity.this.startActivityForResult(launch, 0);
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));
};
// The token is a named value in the bundle. The name of the value
// is stored in the constant AccountManager.KEY_AUTHTOKEN.
String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Log.d("micropub", "GetTokenForAccount Bundle is " + token);
callback.tokenReady(bundle.getString("accountType"), bundle.getString("authAccount"), token);
} catch (OperationCanceledException e) {
e.printStackTrace();
accountManager.getAuthTokenByFeatures("Indieauth", "token", null, this, options, null, new OnTokenAcquired(this, callback), null);
}
public void galleryIntent(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "Select File"), SELECT_FILE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == SELECT_FILE) {
onSelectFromGalleryResult(data);
}
}
}
private void onSelectFromGalleryResult(Intent data) {
Log.i("micropub", "response received " + data.toString());
try (InputStream input = getApplicationContext().getContentResolver().openInputStream(data.getData())) {
byte[] output = getBytes(input);
String mimeType = data.getType();
if (mimeType == null) {
mimeType = data.resolveType(getApplicationContext().getContentResolver());
}
client.postMedia(output, mimeType);
} catch (FileNotFoundException e) {
Log.e("micropub", "Error while copying image", e);
} catch (IOException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
}
Log.e("micropub", "Error while copying image", e);
}
}
}

View File

@ -0,0 +1,48 @@
package eu.stuifzand.micropub;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import java.io.IOException;
public class OnTokenAcquired implements AccountManagerCallback<Bundle> {
private final TokenReady callback;
private Activity activity;
public OnTokenAcquired(Activity activity, TokenReady callback) {
this.activity = activity;
this.callback = callback;
}
@Override
public void run(AccountManagerFuture<Bundle> result) {
// Get the result of the operation from the AccountManagerFuture.
try {
Bundle bundle = result.getResult();
Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (launch != null) {
activity.startActivityForResult(launch, 0);
return;
}
// The token is a named value in the bundle. The name of the value
// is stored in the constant AccountManager.KEY_AUTHTOKEN.
String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Log.d("micropub", "GetTokenForAccount Bundle is " + token);
callback.tokenReady(bundle.getString("accountType"), bundle.getString("authAccount"), token);
} catch (OperationCanceledException e) {
Log.e("micropub", "on token acquired", e);
} catch (IOException e) {
Log.e("micropub", "on token acquired", e);
} catch (AuthenticatorException e) {
Log.e("micropub", "on token acquired", e);
}
}
}

View File

@ -44,7 +44,6 @@ public class PostMessageTask extends AsyncTask<String, Void, String> {
}
RequestBody formBody = builder.build();
micropubBackend = "http://192.168.178.21:5000/micropub";
Request request = new Request.Builder()
.addHeader("Authorization", "Bearer " + accessToken)
.method("POST", formBody)

View File

@ -8,22 +8,42 @@ import android.databinding.ObservableList;
import java.util.Arrays;
import eu.stuifzand.micropub.client.Client;
import eu.stuifzand.micropub.client.Post;
import eu.stuifzand.micropub.client.Syndication;
import okhttp3.HttpUrl;
public class PostViewModel extends ViewModel {
public final ObservableField<String> name = new ObservableField<>();
public final ObservableField<String> content = new ObservableField<>();
public final ObservableField<String> category = new ObservableField<>();
public final ObservableField<String> inReplyTo = new ObservableField<>();
public final ObservableField<String> photo = new ObservableField<>();
public PostViewModel() {
this.name.set("");
this.content.set("");
this.category.set("");
this.inReplyTo.set("");
this.photo.set("");
}
public void clear() {
this.name.set("");
this.content.set("");
this.category.set("");
this.inReplyTo.set("");
this.photo.set("");
}
public void setPhoto(String url) {
this.photo.set(url);
}
public Post getPost() {
Post post = new Post(null, content.get(), category.get(), HttpUrl.parse(inReplyTo.get()));
if (!this.photo.get().equals("")) {
post.setPhoto(this.photo.get());
}
return post;
}
}

View File

@ -12,6 +12,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.FormBody;
@ -20,6 +21,7 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
public class VerifyAuthenticationTask extends AsyncTask<String, Void, VerifyAuthenticationTask.AuthenticationResult> {
@ -78,7 +80,16 @@ public class VerifyAuthenticationTask extends AsyncTask<String, Void, VerifyAuth
.method("POST", formBody)
.build();
OkHttpClient client = new OkHttpClient();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
Call call = client.newCall(request);
Response response = null;
try {

View File

@ -22,6 +22,8 @@ import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import okhttp3.HttpUrl;
public class WebsigninTask extends AsyncTask<String, Void, Bundle> {
public static final String ME = "eu.stuifzand.micropub.ME";
@ -42,10 +44,11 @@ public class WebsigninTask extends AsyncTask<String, Void, Bundle> {
protected Bundle doInBackground(String... strings) {
Log.i("micropub", "Starting WebsigninTask.doInBackground");
Bundle bundle = new Bundle();
HashMap<String,String> linkHeaders = new HashMap<>();
HashMap<String, String> linkHeaders = new HashMap<>();
try {
bundle.putString(ME, strings[0]);
Connection conn = Jsoup.connect(strings[0]);
String profileUrl = strings[0];
bundle.putString(ME, profileUrl);
Connection conn = Jsoup.connect(profileUrl);
Document doc = conn.get();
Connection.Response resp = conn.response();
@ -61,9 +64,12 @@ public class WebsigninTask extends AsyncTask<String, Void, Bundle> {
String url = results.group(1);
String rel = results.group(2);
Log.d("micropub", "Found url=" + url + " and rel=" + rel);
if (!rel.isEmpty() && !linkHeaders.containsKey(rel)) {
linkHeaders.put(rel, url);
HttpUrl base = HttpUrl.parse(profileUrl);
HttpUrl resolvedUrl = base.resolve(url);
if (resolvedUrl != null && !rel.isEmpty() && !linkHeaders.containsKey(rel)) {
Log.d("micropub", "Found url=" + resolvedUrl + " and rel=" + rel);
linkHeaders.put(rel, resolvedUrl.toString());
}
}
}
@ -79,7 +85,7 @@ public class WebsigninTask extends AsyncTask<String, Void, Bundle> {
return bundle;
}
String[] rels = new String[]{"authorization_endpoint","token_endpoint","micropub"};
String[] rels = new String[]{"authorization_endpoint", "token_endpoint", "micropub"};
for (String rel : rels) {
if (linkHeaders.containsKey(rel)) {

View File

@ -1,111 +1,103 @@
package eu.stuifzand.micropub.client;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.databinding.ObservableArrayList;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import org.apache.http.params.HttpParams;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import eu.stuifzand.micropub.MainActivity;
import eu.stuifzand.micropub.TokenReady;
import eu.stuifzand.micropub.auth.VerifyAuthenticationTask;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
public class Client extends AndroidViewModel {
private final OkHttpClient httpClient;
private MutableLiveData<Response> response = new MutableLiveData<>();
private MutableLiveData<Response> mediaResponse = new MutableLiveData<>();
public final ObservableArrayList<Syndication> syndicates = new ObservableArrayList<>();
private String accountType;
private String accountName;
private String token;
private HttpUrl mediaEndpoint;
public Client(@NonNull Application application) {
super(application);
}
class LoadSyndicatesTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... strings) {
AccountManager am = AccountManager.get(Client.this.getApplication());
Account[] accounts = am.getAccountsByType(accountType);
String micropubBackend = null;
for (Account account : accounts) {
if (account.name.equals(accountName)) {
micropubBackend = am.getUserData(account, "micropub");
break;
}
}
if (micropubBackend != null) {
HttpUrl backend = HttpUrl.parse(micropubBackend);
backend = backend.newBuilder()
.setQueryParameter("q", "syndicate-to")
.build();
Request request = new Request.Builder()
.addHeader("Authorization", "Bearer " + token)
.method("GET", null)
.url(backend)
.build();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
httpClient = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
}
Call call = client.newCall(request);
okhttp3.Response httpResponse = null;
try {
httpResponse = call.execute();
if (httpResponse.code() == 200) {
JsonParser parser = new JsonParser();
JsonObject element = parser.parse(httpResponse.body().string()).getAsJsonObject();
JsonArray arr = element.getAsJsonArray("syndicate-to");
public OkHttpClient getClient() {
return httpClient;
}
public LiveData<Response> getMediaResponse() {
return mediaResponse;
}
public void loadConfig(HttpUrl micropubBackend) {
MicropubConfigResponseCallback callback = configElement -> {
// Media endpoint
JsonObject config = configElement.getAsJsonObject();
JsonElement elem = config.get("media-endpoint");
if (elem != null) {
setMediaEndpoint(elem.getAsString());
}
// Syndications.
JsonArray arr = config.getAsJsonArray("syndicate-to");
if (arr != null) {
syndicates.clear();
for (int i = 0; i < arr.size(); i++) {
JsonObject syn = arr.get(i).getAsJsonObject();
syndicates.add(new Syndication(syn.get("uid").getAsString(), syn.get("name").getAsString()));
}
}
} catch (IOException e) {
} finally {
if (httpResponse != null) {
httpResponse.close();
}
}
}
return null;
}
};
new MicropubConfigTask(this.getClient(), micropubBackend, token, callback, "config").execute();
}
public void loadSyndicates() {
new LoadSyndicatesTask().execute();
public void loadSyndicates(HttpUrl micropubBackend) {
MicropubConfigResponseCallback callback = element -> {
JsonArray arr = element.getAsJsonObject().getAsJsonArray("syndicate-to");
syndicates.clear();
for (int i = 0; i < arr.size(); i++) {
JsonObject syn = arr.get(i).getAsJsonObject();
syndicates.add(new Syndication(syn.get("uid").getAsString(), syn.get("name").getAsString()));
}
};
new MicropubConfigTask(this.getClient(), micropubBackend, token, callback, "syndicate-to").execute();
}
public void createPost(Post post, String accessToken, HttpUrl micropubBackend) {
List<String> uids = new ArrayList<String>();
for (Syndication s : syndicates) {
if (s.checked.get()) {
uids.add(s.uid.get());
}
}
post.setSyndicationUids(uids.toArray(new String[uids.size()]));
new PostTask(post, micropubBackend, accessToken, response).execute();
}
@ -119,81 +111,11 @@ public class Client extends AndroidViewModel {
this.token = token;
}
private class PostTask extends AsyncTask<String, Void, Void> {
private Post post;
private HttpUrl micropubBackend;
private String accessToken;
private MutableLiveData<Response> response;
PostTask(Post post, HttpUrl micropubBackend, String accessToken, MutableLiveData<Response> response) {
this.post = post;
this.micropubBackend = micropubBackend;
this.accessToken = accessToken;
this.response = response;
public void postMedia(byte[] output, @NonNull String mimeType) {
new PostMediaTask(mediaResponse, mediaEndpoint, token, output, mimeType).execute();
}
@Override
protected Void doInBackground(String... strings) {
FormBody.Builder builder = new FormBody.Builder();
builder.add("h", "entry")
.add("content", post.getContent());
for (String cat : post.getCategories()) {
builder.add("category[]", cat);
}
for (String uid : post.getSyndicationUids()) {
builder.add("mp-syndicate-to[]", uid);
}
if (post.hasInReplyTo()) {
builder.add("in-reply-to", post.getInReplyTo());
}
if (post.hasName()) {
builder.add("name", post.getName());
}
RequestBody formBody = builder.build();
Request request = new Request.Builder()
.addHeader("Authorization", "Bearer " + accessToken)
.method("POST", formBody)
.url(micropubBackend)
.build();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
Call call = client.newCall(request);
okhttp3.Response httpResponse = null;
try {
httpResponse = call.execute();
if (httpResponse.code() == 201) {
String location = httpResponse.header("Location");
response.postValue(Response.successful(location));
} else {
response.postValue(Response.failed());
}
for (Syndication s : Client.this.syndicates) {
s.checked.set(false);
}
} catch (IOException e) {
response.postValue(Response.failed());
} finally {
if (httpResponse != null) {
httpResponse.close();
}
}
return null;
}
public void setMediaEndpoint(String mediaEndpoint) {
this.mediaEndpoint = HttpUrl.parse(mediaEndpoint);
}
}

View File

@ -0,0 +1,7 @@
package eu.stuifzand.micropub.client;
import com.google.gson.JsonElement;
public interface MicropubConfigResponseCallback {
void handleResponse(JsonElement object);
}

View File

@ -0,0 +1,63 @@
package eu.stuifzand.micropub.client;
import android.os.AsyncTask;
import android.util.Log;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
class MicropubConfigTask extends AsyncTask<String, Void, String> {
private final OkHttpClient client;
private final HttpUrl micropubBackend;
private final String accessToken;
private final String configKey;
private MicropubConfigResponseCallback callback;
public MicropubConfigTask(OkHttpClient client, HttpUrl micropubBackend, String accessToken, MicropubConfigResponseCallback callback, String configKey) {
this.client = client;
this.micropubBackend = micropubBackend;
this.accessToken = accessToken;
this.callback = callback;
this.configKey = configKey;
}
@Override
protected String doInBackground(String... strings) {
HttpUrl backend = micropubBackend.newBuilder()
.setQueryParameter("q", configKey)
.build();
Request request = new Request.Builder()
.addHeader("Authorization", "Bearer " + accessToken)
.method("GET", null)
.url(backend)
.build();
Call call = client.newCall(request);
okhttp3.Response httpResponse = null;
try {
httpResponse = call.execute();
if (httpResponse.code() == 200) {
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(httpResponse.body().string());
callback.handleResponse(element);
}
} catch (IOException e) {
Log.e("micropub", "Error while getting syndicate-to", e);
} finally {
if (httpResponse != null) {
httpResponse.close();
}
}
return null;
}
}

View File

@ -8,6 +8,7 @@ public class Post {
private HttpUrl inReplyTo;
private String[] categories;
private String[] syndicationUids;
private String photo;
public Post(String content) {
this.content = content;
@ -66,4 +67,16 @@ public class Post {
public String[] getSyndicationUids() {
return syndicationUids;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getPhoto() {
return photo;
}
public boolean hasPhoto() {
return this.photo != null;
}
}

View File

@ -0,0 +1,67 @@
package eu.stuifzand.micropub.client;
import android.arch.lifecycle.MutableLiveData;
import android.os.AsyncTask;
import android.util.Log;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
class PostMediaTask extends AsyncTask<String, Void, Void> {
private MutableLiveData<Response> mediaResponse;
private HttpUrl mediaEndpoint;
private String accessToken;
private byte[] output;
private String mimeType;
PostMediaTask(MutableLiveData<Response> mediaResponse, HttpUrl mediaEndpoint, String accessToken, byte[] output, String mimeType) {
this.mediaResponse = mediaResponse;
this.mediaEndpoint = mediaEndpoint;
this.accessToken = accessToken;
this.output = output;
this.mimeType = mimeType;
}
@Override
protected Void doInBackground(String... strings) {
Log.i("micropub", "output size: " + output.length);
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "photo.jpg", RequestBody.create(MediaType.parse(mimeType), output))
.build();
Request request = new Request.Builder()
.url(mediaEndpoint)
.addHeader("Authorization", "Bearer " + accessToken)
.method("POST", formBody)
.build();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
Call call = client.newCall(request);
try {
okhttp3.Response httpResponse = call.execute();
if (httpResponse.code() == 201) {
Log.i("micropub", "response received");
String location = httpResponse.header("Location");
mediaResponse.postValue(Response.successful(location));
} else {
Log.i("micropub", httpResponse.body().string());
}
} catch (IOException e) {
Log.e("micropub", "Error while sending image", e);
}
return null;
}
}

View File

@ -0,0 +1,95 @@
package eu.stuifzand.micropub.client;
import android.arch.lifecycle.MutableLiveData;
import android.os.AsyncTask;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
class PostTask extends AsyncTask<String, Void, Void> {
private Post post;
private HttpUrl micropubBackend;
private String accessToken;
private MutableLiveData<Response> response;
PostTask(Post post, HttpUrl micropubBackend, String accessToken, MutableLiveData<Response> response) {
this.post = post;
this.micropubBackend = micropubBackend;
this.accessToken = accessToken;
this.response = response;
}
@Override
protected Void doInBackground(String... strings) {
FormBody.Builder builder = new FormBody.Builder();
builder.add("h", "entry")
.add("content", post.getContent());
for (String cat : post.getCategories()) {
builder.add("category[]", cat);
}
for (String uid : post.getSyndicationUids()) {
builder.add("mp-syndicate-to[]", uid);
}
if (post.hasInReplyTo()) {
builder.add("in-reply-to", post.getInReplyTo());
}
if (post.hasName()) {
builder.add("name", post.getName());
}
if (post.hasPhoto()) {
builder.add("photo", post.getPhoto());
}
RequestBody formBody = builder.build();
Request request = new Request.Builder()
.addHeader("Authorization", "Bearer " + accessToken)
.method("POST", formBody)
.url(micropubBackend)
.build();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
Call call = client.newCall(request);
okhttp3.Response httpResponse = null;
try {
httpResponse = call.execute();
if (httpResponse.code() == 201) {
String location = httpResponse.header("Location");
response.postValue(Response.successful(location));
} else {
response.postValue(Response.failed());
}
} catch (IOException e) {
response.postValue(Response.failed());
} finally {
if (httpResponse != null) {
httpResponse.close();
}
}
return null;
}
}

View File

@ -24,4 +24,8 @@ public class Response {
public boolean isSuccess() {
return success;
}
public String getUrl() {
return url;
}
}

View File

@ -0,0 +1,23 @@
package eu.stuifzand.micropub.utils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class IOUtils {
public static byte[] getBytes(InputStream inputStream) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();) {
byte[] buffer = new byte[16 * 4096];
int read;
while ((read = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, read);
}
return outputStream.toByteArray();
} catch (IOException e) {
Log.e("micropub", "Error while copying image", e);
}
return null;
}
}

View File

@ -26,15 +26,15 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="always"
android:scrollbars="vertical"
android:paddingTop="8dp"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.design.widget.TextInputLayout
@ -102,7 +102,7 @@
android:layout_width="match_parent"
android:layout_height="56sp"
android:ems="10"
android:imeOptions="actionDone"
android:imeOptions="actionNext"
android:inputType="text"
android:lines="1"
android:maxLines="1"
@ -125,16 +125,16 @@
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:text="@string/syndication"
android:textSize="16sp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp" />
android:textSize="16sp" />
<ListView
android:id="@+id/listSyndication"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_height="115dp"
app:list="@{client.syndicates}" />
</LinearLayout>
@ -144,14 +144,48 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:onClick="sendPost"
android:text="@string/post"
app:layout_constraintEnd_toEndOf="@id/editCategoryLayout"
app:layout_constraintTop_toBottomOf="@id/listLayout"
tools:layout_editor_absoluteY="445dp" />
app:layout_constraintTop_toBottomOf="@+id/editPhotoLayout" />
<Button
android:id="@+id/btnGetImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginTop="8dp"
android:onClick="galleryIntent"
android:text="Select photo"
app:layout_constraintEnd_toStartOf="@+id/btnPost"
app:layout_constraintTop_toBottomOf="@+id/editPhotoLayout" />
<android.support.design.widget.TextInputLayout
android:id="@+id/editPhotoLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="Photo url"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/listLayout">
<android.support.design.widget.TextInputEditText
android:id="@+id/editPhoto"
android:layout_width="match_parent"
android:layout_height="56sp"
android:ems="10"
android:imeOptions="actionDone"
android:inputType="text"
android:lines="1"
android:maxLines="1"
android:singleLine="true"
android:text="@={viewModel.photo}" />
</android.support.design.widget.TextInputLayout>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
</ScrollView>
</layout>