diff --git a/app/build.gradle b/app/build.gradle
index e01a5421e..f14d689d4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -33,4 +33,5 @@ dependencies {
compile 'com.evernote:android-job:1.1.11'
compile 'com.github.chrisbanes:PhotoView:2.0.0'
compile 'com.google.code.gson:gson:2.8.0'
+ compile 'org.jsoup:jsoup:1.10.3'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7c8f05a01..b5f8948b4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -85,6 +85,11 @@
android:launchMode="singleTask"
android:noHistory="true"
/>
+
2 && !isLoadingInstance){
+ if( s.length() > 2 && !isLoadingInstance && 1 ==2){
String action = "/instances/search";
RequestParams parameters = new RequestParams();
parameters.add("q", s.toString().trim());
@@ -220,15 +223,20 @@ public class RemoteFollowActivity extends AppCompatActivity implements OnRetriev
rf_search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+
if( rf_instance.getText().toString().trim().equals("") || rf_username.getText().toString().trim().equals("")){
Toast.makeText(getApplicationContext(),R.string.toast_empty_search,Toast.LENGTH_LONG).show();
return;
}
rf_search.setEnabled(false);
- String screen_name = rf_username.getText().toString().trim();
- String instance_name = rf_instance.getText().toString().trim();
+ screen_name = rf_username.getText().toString().trim();
+ instance_name = rf_instance.getText().toString().trim();
+ lv_account.setVisibility(View.GONE);
loader.setVisibility(View.VISIBLE);
- new RetrieveSearchAccountsAsyncTask(getApplicationContext(), screen_name + "@" + instance_name, 1, RemoteFollowActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ rf_no_result.setVisibility(View.GONE);
+ if( screen_name.startsWith("@"))
+ screen_name = screen_name.substring(1);
+ new RetrieveRemoteAccountsAsyncTask(RemoteFollowActivity.this, screen_name, instance_name, RemoteFollowActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
}
@@ -244,7 +252,7 @@ public class RemoteFollowActivity extends AppCompatActivity implements OnRetriev
}
}
-
+/*
@Override
public void onRetrieveSearchAccounts(APIResponse apiResponse) {
rf_search.setEnabled(true);
@@ -257,10 +265,52 @@ public class RemoteFollowActivity extends AppCompatActivity implements OnRetriev
return;
}
final List accounts = apiResponse.getAccounts();
+ Log.v(Helper.TAG,"accounts: " + accounts);
if( accounts != null && accounts.size() > 0 && accounts.get(0) != null) {
- AccountsListAdapter accountsListAdapter = new AccountsListAdapter(getApplicationContext(), RetrieveAccountsAsyncTask.Type.FOLLOWERS, null, accounts);
- lv_account.setAdapter(accountsListAdapter);
- lv_account.setVisibility(View.VISIBLE);
+ List selectedAccount = new ArrayList<>();
+ for(Account account: accounts){
+ if(account.getAcct().contains("@" + instance_name) || (account.getUsername().equals(account.getAcct()) && account.getUsername().equals(screen_name)))
+ selectedAccount.add(account);
+ }
+ if( selectedAccount.size() > 0) {
+ AccountsListAdapter accountsListAdapter = new AccountsListAdapter(RemoteFollowActivity.this, RetrieveAccountsAsyncTask.Type.FOLLOWERS, null, selectedAccount);
+ lv_account.setAdapter(accountsListAdapter);
+ lv_account.setVisibility(View.VISIBLE);
+ }else {
+ rf_no_result.setVisibility(View.VISIBLE);
+ }
+ }else if( firstSearch){
+ firstSearch = false;
+ new RetrieveSearchAccountsAsyncTask(RemoteFollowActivity.this, screen_name, 50, RemoteFollowActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }else {
+ rf_no_result.setVisibility(View.VISIBLE);
}
+ }*/
+
+
+ @Override
+ public void onRetrieveRemoteAccount(boolean error, String name, String avatar, String bio, int statusCount, int followingCount, int followersCount) {
+ if( error){
+ rf_no_result.setVisibility(View.VISIBLE);
+ Toast.makeText(getApplicationContext(), R.string.toast_error,Toast.LENGTH_LONG).show();
+ return;
+ }
+ loader.setVisibility(View.GONE);
+ Account account = new Account();
+ account.setInstance(instance_name);
+ account.setAcct(screen_name + "@" + instance_name);
+ account.setAvatar(avatar);
+ account.setDisplay_name(name);
+ account.setStatuses_count(statusCount);
+ account.setFollowers_count(followersCount);
+ account.setFollowing_count(followingCount);
+ account.setUsername(name);
+ account.setNote(bio);
+ List selectedAccount = new ArrayList<>();
+ selectedAccount.add(account);
+ AccountSearchWebAdapter accountSearchWebAdapter = new AccountSearchWebAdapter(RemoteFollowActivity.this, selectedAccount);
+ lv_account.setAdapter(accountSearchWebAdapter);
+ lv_account.setVisibility(View.VISIBLE);
+
}
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteAccountsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteAccountsAsyncTask.java
new file mode 100644
index 000000000..9cc037c97
--- /dev/null
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteAccountsAsyncTask.java
@@ -0,0 +1,79 @@
+/* Copyright 2017 Thomas Schneider
+ *
+ * This file is a part of Mastalab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Mastalab; if not,
+ * see . */
+package fr.gouv.etalab.mastodon.asynctasks;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.util.Log;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.select.Elements;
+import java.io.IOException;
+import fr.gouv.etalab.mastodon.helper.Helper;
+import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRemoteAccountInterface;
+
+
+/**
+ * Created by Thomas on 22/07/2017.
+ * Retrieves a remote account via its webpage
+ */
+
+public class RetrieveRemoteAccountsAsyncTask extends AsyncTask {
+
+ private Context context;
+ private OnRetrieveRemoteAccountInterface listener;
+ private String url;
+ private String avatar, name, bio;
+ private int statusCount, followingCount, followersCount;
+ private boolean error = false;
+ private String instance;
+
+ public RetrieveRemoteAccountsAsyncTask(Context context, String username, String instance, OnRetrieveRemoteAccountInterface onRetrieveRemoteAccountInterface){
+ this.context = context;
+ this.url = "https://" + instance + "/@" + username;
+ this.listener = onRetrieveRemoteAccountInterface;
+ this.instance = instance;
+ }
+
+
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ String userAgent = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36";
+ try {
+ Document document = Jsoup.connect(url).userAgent(userAgent).get();
+ Elements avatarElement = document.getElementsByClass("avatar");
+ avatar = avatarElement.get(0).getElementsByClass("u-photo").get(0).attr("src");
+ avatar = "https://" + instance + avatar;
+ Elements nameElement = document.getElementsByClass("name");
+ name = nameElement.get(0).html();
+ Elements bioElement = document.getElementsByClass("bio");
+ bio = bioElement.get(0).html();;
+ Elements countElement = document.getElementsByClass("counter-number");
+ statusCount = Integer.parseInt(countElement.get(0).html());
+ followingCount = Integer.parseInt(countElement.get(1).html());
+ followersCount = Integer.parseInt(countElement.get(2).html());
+ } catch (IOException e) {
+ error = true;
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ listener.onRetrieveRemoteAccount(error, name, avatar, bio, statusCount, followingCount, followersCount);
+ }
+
+}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveSearchAccountsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveSearchAccountsAsyncTask.java
index a695440ad..e5cdeceba 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveSearchAccountsAsyncTask.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveSearchAccountsAsyncTask.java
@@ -32,27 +32,18 @@ public class RetrieveSearchAccountsAsyncTask extends AsyncTask
private String query;
private APIResponse apiResponse;
private OnRetrieveSearcAccountshInterface listener;
- private int limit;
public RetrieveSearchAccountsAsyncTask(Context context, String query, OnRetrieveSearcAccountshInterface onRetrieveSearcAccountshInterface){
this.context = context;
this.query = query;
this.listener = onRetrieveSearcAccountshInterface;
- this.limit = 10;
- }
-
- public RetrieveSearchAccountsAsyncTask(Context context, String query, int limit, OnRetrieveSearcAccountshInterface onRetrieveSearcAccountshInterface){
- this.context = context;
- this.query = query;
- this.listener = onRetrieveSearcAccountshInterface;
- this.limit = limit;
}
@Override
protected Void doInBackground(Void... params) {
API api = new API(context);
- apiResponse = api.searchAccounts(query, limit);
+ apiResponse = api.searchAccounts(query, 10);
return null;
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java
index f9c8a198b..904246867 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java
@@ -92,7 +92,8 @@ public class API {
UNSTATUS,
AUTHORIZE,
REJECT,
- REPORT
+ REPORT,
+ REMOTE_FOLLOW
}
public API(Context context) {
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/AccountSearchWebAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/AccountSearchWebAdapter.java
new file mode 100644
index 000000000..74ea48428
--- /dev/null
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/AccountSearchWebAdapter.java
@@ -0,0 +1,176 @@
+package fr.gouv.etalab.mastodon.drawers;
+/* Copyright 2017 Thomas Schneider
+ *
+ * This file is a part of Mastalab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Mastalab; if not,
+ * see . */
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.support.design.widget.FloatingActionButton;
+import android.text.Html;
+import android.text.util.Linkify;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
+import com.nostra13.universalimageloader.core.ImageLoader;
+import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
+import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
+
+import java.io.File;
+import java.util.List;
+
+import fr.gouv.etalab.mastodon.asynctasks.PostActionAsyncTask;
+import fr.gouv.etalab.mastodon.client.API;
+import fr.gouv.etalab.mastodon.client.Entities.Account;
+import fr.gouv.etalab.mastodon.client.Entities.Error;
+import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
+import fr.gouv.etalab.mastodon.helper.Helper;
+import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface;
+import mastodon.etalab.gouv.fr.mastodon.R;
+
+
+/**
+ * Created by Thomas on 22/08/2017.
+ * Adapter for accounts from web
+ */
+public class AccountSearchWebAdapter extends BaseAdapter implements OnPostActionInterface {
+
+ private List accounts;
+ private LayoutInflater layoutInflater;
+ private Context context;
+ private ViewHolder holder;
+
+ public AccountSearchWebAdapter(Context context, List accounts){
+ this.context = context;
+ this.accounts = accounts;
+ layoutInflater = LayoutInflater.from(context);
+ }
+
+
+
+ @Override
+ public int getCount() {
+ return accounts.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return accounts.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+
+ ImageLoader imageLoader = ImageLoader.getInstance();
+ File cacheDir = new File(context.getCacheDir(), context.getString(R.string.app_name));
+ ImageLoaderConfiguration configImg = new ImageLoaderConfiguration.Builder(context)
+ .imageDownloader(new PatchBaseImageDownloader(context))
+ .threadPoolSize(5)
+ .threadPriority(Thread.MIN_PRIORITY + 3)
+ .denyCacheImageMultipleSizesInMemory()
+ .diskCache(new UnlimitedDiskCache(cacheDir))
+ .build();
+ if( !imageLoader.isInited())
+ imageLoader.init(configImg);
+ DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
+ .cacheOnDisk(true).resetViewBeforeLoading(true).build();
+ final Account account = accounts.get(position);
+
+ if (convertView == null) {
+ convertView = layoutInflater.inflate(R.layout.drawer_account_search_html, parent, false);
+ holder = new ViewHolder();
+ holder.account_pp = (ImageView) convertView.findViewById(R.id.account_pp);
+ holder.account_dn = (TextView) convertView.findViewById(R.id.account_dn);
+
+ holder.account_ds = (TextView) convertView.findViewById(R.id.account_ds);
+ holder.account_sc = (TextView) convertView.findViewById(R.id.account_sc);
+ holder.account_fgc = (TextView) convertView.findViewById(R.id.account_fgc);
+ holder.account_frc = (TextView) convertView.findViewById(R.id.account_frc);
+ holder.account_follow = (FloatingActionButton) convertView.findViewById(R.id.account_follow);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+
+
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ holder.account_ds.setText(Html.fromHtml(account.getNote(), Html.FROM_HTML_MODE_LEGACY));
+ holder.account_dn.setText(Html.fromHtml(Helper.shortnameToUnicode(account.getDisplay_name(), true), Html.FROM_HTML_MODE_LEGACY));
+ }else {
+ //noinspection deprecation
+ holder.account_ds.setText(Html.fromHtml(account.getNote()));
+ holder.account_dn.setText(Html.fromHtml(Helper.shortnameToUnicode(account.getDisplay_name(), true)));
+ }
+ holder.account_ds.setAutoLinkMask(Linkify.WEB_URLS);
+ holder.account_sc.setText(String.valueOf(account.getStatuses_count()));
+ holder.account_fgc.setText(String.valueOf(account.getFollowing_count()));
+ holder.account_frc.setText(String.valueOf(account.getFollowers_count()));
+ //Profile picture
+ imageLoader.displayImage(account.getAvatar(), holder.account_pp, options);
+
+ holder.account_follow.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ holder.account_follow.setEnabled(false);
+ new PostActionAsyncTask(context, API.StatusAction.REMOTE_FOLLOW, null, AccountSearchWebAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ });
+
+ return convertView;
+ }
+
+ @Override
+ public void onPostAction(int statusCode, API.StatusAction statusAction, String userId, Error error) {
+ if( error != null){
+ final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+ boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
+ if( show_error_messages)
+ Toast.makeText(context, error.getError(),Toast.LENGTH_LONG).show();
+ holder.account_follow.setEnabled(true);
+ return;
+ }
+ holder.account_follow.setVisibility(View.GONE);
+ Toast.makeText(context, R.string.toast_follow, Toast.LENGTH_LONG).show();
+ }
+
+
+ private class ViewHolder {
+ ImageView account_pp;
+ TextView account_dn;
+ TextView account_ds;
+ TextView account_sc;
+ TextView account_fgc;
+ TextView account_frc;
+ FloatingActionButton account_follow;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveRemoteAccountInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveRemoteAccountInterface.java
new file mode 100644
index 000000000..202a03616
--- /dev/null
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveRemoteAccountInterface.java
@@ -0,0 +1,24 @@
+/* Copyright 2017 Thomas Schneider
+ *
+ * This file is a part of Mastalab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Mastalab; if not,
+ * see . */
+package fr.gouv.etalab.mastodon.interfaces;
+
+
+/**
+ * Created by Thomas on 22/08/2017.
+ * Interface for retrieving a remote account
+ */
+public interface OnRetrieveRemoteAccountInterface {
+ void onRetrieveRemoteAccount(boolean error, String name, String avatar, String bio, int statusCount, int followingCount, int followersCount);
+}
diff --git a/app/src/main/res/layout/activity_remote_follow.xml b/app/src/main/res/layout/activity_remote_follow.xml
index 3f9277930..deff21837 100644
--- a/app/src/main/res/layout/activity_remote_follow.xml
+++ b/app/src/main/res/layout/activity_remote_follow.xml
@@ -73,6 +73,19 @@
android:scrollbars="none"
android:divider="@null"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file