Merge branch 'develop' into instance_health

This commit is contained in:
stom79 2017-11-25 07:51:25 +01:00
commit 8f31196425
32 changed files with 697 additions and 106 deletions

View File

@ -7,8 +7,8 @@ android {
applicationId "fr.gouv.etalab.mastodon"
minSdkVersion 15
targetSdkVersion 27
versionCode 78
versionName "1.6.2-beta-1"
versionCode 79
versionName "1.6.2-beta-2"
}
flavorDimensions "default"
buildTypes {

View File

@ -90,6 +90,7 @@ import fr.gouv.etalab.mastodon.fragments.DisplayDraftsFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayFollowRequestSentFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayScheduledTootsFragment;
import fr.gouv.etalab.mastodon.fragments.DisplaySearchFragment;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveInstanceInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMetaDataInterface;
@ -120,7 +121,7 @@ import android.support.v4.app.FragmentStatePagerAdapter;
public abstract class BaseMainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, OnUpdateAccountInfoInterface, OnRetrieveMetaDataInterface, OnRetrieveInstanceInterface {
private FloatingActionButton toot, delete_all;
private FloatingActionButton toot, delete_all, add_new;
private HashMap<String, String> tagTile = new HashMap<>();
private HashMap<String, Integer> tagItem = new HashMap<>();
private TextView toolbarTitle;
@ -568,6 +569,7 @@ public abstract class BaseMainActivity extends AppCompatActivity
toot = findViewById(R.id.toot);
delete_all = findViewById(R.id.delete_all);
add_new = findViewById(R.id.add_new);
toot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -1086,6 +1088,7 @@ public abstract class BaseMainActivity extends AppCompatActivity
tabLayout.setVisibility(View.VISIBLE);
toolbarTitle.setVisibility(View.GONE);
delete_all.setVisibility(View.GONE);
add_new.setVisibility(View.GONE);
final NavigationView navigationView = findViewById(R.id.nav_view);
unCheckAllMenuItems(navigationView);
toot.setVisibility(View.VISIBLE);
@ -1258,6 +1261,11 @@ public abstract class BaseMainActivity extends AppCompatActivity
}else{
delete_all.setVisibility(View.VISIBLE);
}
if( id != R.id.nav_search){
add_new.setVisibility(View.GONE);
}else{
add_new.setVisibility(View.VISIBLE);
}
if (id == R.id.nav_settings) {
toot.setVisibility(View.GONE);
TabLayoutSettingsFragment tabLayoutSettingsFragment= new TabLayoutSettingsFragment();
@ -1296,12 +1304,17 @@ public abstract class BaseMainActivity extends AppCompatActivity
fragmentManager.beginTransaction()
.replace(R.id.main_app_container, displayScheduledTootsFragment, fragmentTag).commit();
}else if (id == R.id.nav_drafts) {
toot.setVisibility(View.VISIBLE);
DisplayDraftsFragment displayDraftsFragment = new DisplayDraftsFragment();
fragmentTag = "DRAFTS";
fragmentManager.beginTransaction()
.replace(R.id.main_app_container, displayDraftsFragment, fragmentTag).commit();
toot.setVisibility(View.GONE);
}else if (id == R.id.nav_search) {
DisplaySearchFragment displaySearchFragment = new DisplaySearchFragment();
fragmentTag = "SEARCH";
fragmentManager.beginTransaction()
.replace(R.id.main_app_container, displaySearchFragment, fragmentTag).commit();
toot.setVisibility(View.GONE);
}else if( id == R.id.nav_follow_request){
toot.setVisibility(View.GONE);
DisplayFollowRequestSentFragment followRequestSentFragment = new DisplayFollowRequestSentFragment();

View File

@ -143,7 +143,6 @@ public class HashTagActivity extends AppCompatActivity implements OnRetrieveFeed
nextElementLoader.setVisibility(View.GONE);
}
}
}
});
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.TAG, tag,null, max_id, HashTagActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

View File

@ -24,10 +24,13 @@ import android.view.View;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import fr.gouv.etalab.mastodon.R;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveSearchAsyncTask;
import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.client.Entities.Results;
@ -35,7 +38,7 @@ import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.drawers.SearchListAdapter;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearchInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearchStatusInterface;
/**
@ -43,7 +46,7 @@ import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearchInterface;
* Show search results within two tabs: Toots and accounts
*/
public class SearchResultActivity extends AppCompatActivity implements OnRetrieveSearchInterface {
public class SearchResultActivity extends AppCompatActivity implements OnRetrieveSearchInterface, OnRetrieveSearchStatusInterface {
private String search;
@ -124,5 +127,23 @@ public class SearchResultActivity extends AppCompatActivity implements OnRetriev
}
@Override
public void onRetrieveSearchStatus(APIResponse apiResponse, Error error) {
loader.setVisibility(View.GONE);
if( apiResponse.getError() != null){
final SharedPreferences sharedpreferences = 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(getApplicationContext(), error.getError(),Toast.LENGTH_LONG).show();
return;
}
lv_search.setVisibility(View.VISIBLE);
List<String> tags = new ArrayList<>();
List<Account> accounts = new ArrayList<>();
List<Status> statuses = apiResponse.getStatuses();
SearchListAdapter searchListAdapter = new SearchListAdapter(SearchResultActivity.this, statuses, accounts, tags);
lv_search.setAdapter(searchListAdapter);
searchListAdapter.notifyDataSetChanged();
}
}

View File

@ -20,17 +20,13 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.util.Log;
import java.lang.ref.WeakReference;
import fr.gouv.etalab.mastodon.activities.MainActivity;
import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Emojis;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.CustomEmojiDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;

View File

@ -27,6 +27,8 @@ import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import fr.gouv.etalab.mastodon.R;
import fr.gouv.etalab.mastodon.client.Entities.*;
import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.helper.Helper;
@ -120,6 +122,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return apiResponse;
@ -145,6 +148,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return apiResponse;
@ -163,6 +167,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return account;
@ -182,6 +187,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return account;
@ -207,6 +213,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return relationship;
@ -240,6 +247,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setRelationships(relationships);
@ -329,6 +337,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -353,6 +362,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -374,6 +384,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return statusContext;
@ -427,6 +438,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -486,6 +498,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -535,6 +548,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -609,6 +623,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setAccounts(accounts);
@ -652,6 +667,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setAccounts(accounts);
@ -695,6 +711,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -838,6 +855,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
}else{
@ -848,10 +866,10 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
}
return actionCode;
}
@ -886,7 +904,6 @@ public class API {
params.put("spoiler_text", URLEncoder.encode(status.getSpoiler_text(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
params.put("spoiler_text", status.getSpoiler_text());
e.printStackTrace();
}
params.put("visibility", status.getVisibility());
statuses = new ArrayList<>();
@ -901,6 +918,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
@ -928,6 +946,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return apiResponse;
@ -1021,6 +1040,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setNotifications(notifications);
@ -1052,6 +1072,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return attachment;
@ -1074,6 +1095,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
return results;
@ -1104,6 +1126,7 @@ public class API {
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
setDefaultError();
e.printStackTrace();
}
apiResponse.setAccounts(accounts);
@ -1148,6 +1171,7 @@ public class API {
results.setStatuses(parseStatuses(resobj.getJSONArray("statuses")));
results.setHashtags(parseTags(resobj.getJSONArray("hashtags")));
} catch (JSONException e) {
setDefaultError();
e.printStackTrace();
}
return results;
@ -1614,6 +1638,11 @@ public class API {
apiResponse.setError(APIError);
}
private void setDefaultError(){
APIError = new Error();
APIError.setError(context.getString(R.string.toast_error));
apiResponse.setError(APIError);
}
public Error getError(){

View File

@ -29,6 +29,7 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.List;
@ -54,6 +55,7 @@ public class DraftsListAdapter extends BaseAdapter {
private Context context;
private DraftsListAdapter draftsListAdapter;
private boolean clickable;
private RelativeLayout textviewNoAction;
public DraftsListAdapter(Context context, List<StoredStatus> storedStatuses){
this.storedStatuses = storedStatuses;
@ -63,12 +65,13 @@ public class DraftsListAdapter extends BaseAdapter {
this.clickable = false;
}
public DraftsListAdapter(Context context, List<StoredStatus> storedStatuses, boolean clickable){
public DraftsListAdapter(Context context, List<StoredStatus> storedStatuses, boolean clickable, RelativeLayout textviewNoAction){
this.storedStatuses = storedStatuses;
this.context = context;
layoutInflater = LayoutInflater.from(context);
draftsListAdapter = this;
this.clickable = clickable;
this.textviewNoAction = textviewNoAction;
}
@Override
@ -145,6 +148,8 @@ public class DraftsListAdapter extends BaseAdapter {
new StatusStoredDAO(context, db).remove(draft.getId());
storedStatuses.remove(draft);
draftsListAdapter.notifyDataSetChanged();
if( storedStatuses.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE)
textviewNoAction.setVisibility(View.VISIBLE);
dialog.dismiss();
}
})

View File

@ -0,0 +1,152 @@
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 <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.List;
import fr.gouv.etalab.mastodon.R;
import fr.gouv.etalab.mastodon.activities.HashTagActivity;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.SearchDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
/**
* Created by Thomas on 22/11/2017.
* Adapter for search
*/
public class SearchTootsListAdapter extends BaseAdapter {
private List<String> searches;
private LayoutInflater layoutInflater;
private Context context;
private SearchTootsListAdapter searchTootsListAdapter;
private RelativeLayout textviewNoAction;
public SearchTootsListAdapter(Context context, List<String> searches, RelativeLayout textviewNoAction){
this.searches = searches;
layoutInflater = LayoutInflater.from(context);
this.context = context;
this.searchTootsListAdapter = this;
this.textviewNoAction = textviewNoAction;
}
@Override
public int getCount() {
return searches.size();
}
@Override
public Object getItem(int position) {
return searches.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final String search = searches.get(position);
final ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.drawer_search, parent, false);
holder = new ViewHolder();
holder.search_title = convertView.findViewById(R.id.search_keyword);
holder.search_container = convertView.findViewById(R.id.search_container);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_LIGHT){
holder.search_container.setBackgroundResource(R.color.mastodonC3__);
changeDrawableColor(context, R.drawable.ic_keyboard_arrow_right,R.color.black);
}else {
holder.search_container.setBackgroundResource(R.color.mastodonC1_);
changeDrawableColor(context, R.drawable.ic_keyboard_arrow_right,R.color.dark_text);
}
holder.search_title.setText(search);
holder.search_container.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, HashTagActivity.class);
Bundle b = new Bundle();
b.putString("tag", search.trim());
intent.putExtras(b);
context.startActivity(intent);
}
});
final SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
holder.search_container.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(context.getString(R.string.delete) + ": " + search);
builder.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new SearchDAO(context, db).remove(search.trim());
searches.remove(search);
searchTootsListAdapter.notifyDataSetChanged();
if( searches.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE)
textviewNoAction.setVisibility(View.VISIBLE);
dialog.dismiss();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
return false;
}
});
return convertView;
}
private class ViewHolder {
LinearLayout search_container;
TextView search_title;
}
}

View File

@ -1,88 +0,0 @@
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 <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
import fr.gouv.etalab.mastodon.R;
/**
* Created by Thomas on 26/05/2017.
* Adapter for tags when searching
*/
public class TagsListAdapter extends BaseAdapter {
private List<String> tags;
private LayoutInflater layoutInflater;
public TagsListAdapter(Context context, List<String> tags){
this.tags = tags;
layoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return tags.size();
}
@Override
public Object getItem(int position) {
return tags.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final String tag = tags.get(position);
final ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.drawer_tag, parent, false);
holder = new ViewHolder();
holder.tag_name = (TextView) convertView.findViewById(R.id.tag_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tag_name.setText(tag);
holder.tag_name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
return convertView;
}
private class ViewHolder {
TextView tag_name;
}
}

View File

@ -16,6 +16,7 @@ package fr.gouv.etalab.mastodon.drawers;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -63,6 +64,7 @@ public class TagsSearchAdapter extends ArrayAdapter<String> implements Filterabl
}
@NonNull
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
@ -71,7 +73,7 @@ public class TagsSearchAdapter extends ArrayAdapter<String> implements Filterabl
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.drawer_tag_search, parent, false);
holder = new ViewHolder();
holder.tag_name = (TextView) convertView.findViewById(R.id.tag_name);
holder.tag_name = convertView.findViewById(R.id.tag_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
@ -81,6 +83,7 @@ public class TagsSearchAdapter extends ArrayAdapter<String> implements Filterabl
return convertView;
}
@NonNull
@Override
public Filter getFilter() {
return searchFilter;

View File

@ -76,7 +76,7 @@ public class DisplayDraftsFragment extends Fragment {
new StatusStoredDAO(context, db).removeAllSent();
drafts = new StatusStoredDAO(context, db).getAllDrafts();
if( drafts != null && drafts.size() > 0) {
draftsListAdapter = new DraftsListAdapter(context, drafts, true);
draftsListAdapter = new DraftsListAdapter(context, drafts, true, textviewNoAction);
lv_draft_toots.setAdapter(draftsListAdapter);
draftsListAdapter.notifyDataSetChanged();
}else {
@ -100,7 +100,7 @@ public class DisplayDraftsFragment extends Fragment {
new StatusStoredDAO(context, db).removeAllDrafts();
drafts = new ArrayList<>();
drafts.clear();
draftsListAdapter = new DraftsListAdapter(context, drafts, true);
draftsListAdapter = new DraftsListAdapter(context, drafts, true, textviewNoAction);
lv_draft_toots.setAdapter(draftsListAdapter);
draftsListAdapter.notifyDataSetChanged();
textviewNoAction.setVisibility(View.VISIBLE);

View File

@ -0,0 +1,134 @@
package fr.gouv.etalab.mastodon.fragments;
/* 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 <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.text.InputFilter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.List;
import fr.gouv.etalab.mastodon.activities.MainActivity;
import fr.gouv.etalab.mastodon.drawers.SearchTootsListAdapter;
import fr.gouv.etalab.mastodon.sqlite.SearchDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import fr.gouv.etalab.mastodon.R;
/**
* Created by Thomas on 22/11/2017.
* Fragment to display search with keywords
*/
public class DisplaySearchFragment extends Fragment {
private Context context;
private SearchTootsListAdapter searchTootsListAdapter;
private List<String> searches;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_search, container, false);
context = getContext();
final ListView lv_search_toots = rootView.findViewById(R.id.lv_search_toots);
RelativeLayout mainLoader = rootView.findViewById(R.id.loader);
final RelativeLayout textviewNoAction = rootView.findViewById(R.id.no_action);
mainLoader.setVisibility(View.VISIBLE);
final SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
searches = new SearchDAO(context, db).getAllSearch();
if( searches == null)
searches = new ArrayList<>();
searchTootsListAdapter = new SearchTootsListAdapter(context, searches, textviewNoAction);
lv_search_toots.setAdapter(searchTootsListAdapter);
searchTootsListAdapter.notifyDataSetChanged();
if( searches.size() == 0) {
textviewNoAction.setVisibility(View.VISIBLE);
}
mainLoader.setVisibility(View.GONE);
FloatingActionButton add_new = null;
try {
add_new = ((MainActivity) context).findViewById(R.id.add_new);
}catch (Exception ignored){}
if( add_new != null)
add_new.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
LayoutInflater inflater = getLayoutInflater();
@SuppressLint("InflateParams") View dialogView = inflater.inflate(R.layout.search_toot, null);
dialogBuilder.setView(dialogView);
final EditText editText = dialogView.findViewById(R.id.search_toot);
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(30)});
dialogBuilder.setPositiveButton(R.string.validate, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
String keyword = editText.getText().toString().trim();
//Empty
if( keyword.length() == 0)
return;
//Already in db
List<String> s_ = new SearchDAO(context, db).getSearchByKeyword(keyword);
if( s_ == null)
s_ = new ArrayList<>();
if( s_.size() > 0){
return;
}
new SearchDAO(context, db).insertSearch(keyword);
searches.add(keyword);
if( textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE);
searchTootsListAdapter.notifyDataSetChanged();
}
});
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.show();
}
});
return rootView;
}
@Override
public void onCreate(Bundle saveInstance)
{
super.onCreate(saveInstance);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
}

View File

@ -0,0 +1,26 @@
/* 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 <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.interfaces;
import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.client.Entities.Error;
/**
* Created by Thomas on 22/11/2017.
* Interface for search
*/
public interface OnRetrieveSearchStatusInterface {
void onRetrieveSearchStatus(APIResponse apiResponse, Error error);
}

View File

@ -0,0 +1,139 @@
package fr.gouv.etalab.mastodon.sqlite;
/* 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 <http://www.gnu.org/licenses>. */
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import fr.gouv.etalab.mastodon.helper.Helper;
/**
* Created by Thomas on 22/11/2017.
* Manage search in DB
*/
public class SearchDAO {
private SQLiteDatabase db;
public Context context;
private String userId;
public SearchDAO(Context context, SQLiteDatabase db) {
//Creation of the DB with tables
this.context = context;
this.db = db;
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
}
//------- INSERTIONS -------
/**
* Insert a keyword in database
* @param keyword String
*/
public void insertSearch(String keyword) {
ContentValues values = new ContentValues();
values.put(Sqlite.COL_KEYWORDS, keyword);
values.put(Sqlite.COL_USER_ID, userId);
values.put(Sqlite.COL_DATE_CREATION, Helper.dateToString(context, new Date()));
//Inserts search
try{
db.insert(Sqlite.TABLE_SEARCH, null, values);
}catch (Exception ignored) {}
}
//------- REMOVE -------
/***
* Remove search by keyword
* @return int
*/
public int remove(String keyword){
return db.delete(Sqlite.TABLE_SEARCH, Sqlite.COL_KEYWORDS + " = \"" + keyword + "\" AND " + Sqlite.COL_USER_ID + " = \"" + userId+ "\"", null);
}
//------- GETTERS -------
/**
* Returns all search in db for a user
* @return search List<String>
*/
public List<String> getAllSearch(){
try {
Cursor c = db.query(Sqlite.TABLE_SEARCH, null, Sqlite.COL_USER_ID + " = '" + userId+ "'", null, null, null, Sqlite.COL_KEYWORDS + " ASC", null);
return cursorToListSearch(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns search by its keyword in db
* @return keywords List<String>
*/
public List<String> getSearchStartingBy(String keyword){
try {
Cursor c = db.query(Sqlite.TABLE_SEARCH, null, Sqlite.COL_KEYWORDS + " LIKE \"%" + keyword + "%\" AND " + Sqlite.COL_USER_ID + " = \"" + userId+ "\"", null, null, null, null, null);
return cursorToListSearch(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns search by its keyword in db
* @return keywords List<String>
*/
public List<String> getSearchByKeyword(String keyword){
try {
Cursor c = db.query(Sqlite.TABLE_SEARCH, null, Sqlite.COL_KEYWORDS + " = \"" + keyword + "\" AND " + Sqlite.COL_USER_ID + " = \"" + userId+ "\"", null, null, null, null, null);
return cursorToListSearch(c);
} catch (Exception e) {
return null;
}
}
/***
* Method to hydrate stored search from database
* @param c Cursor
* @return List<String>
*/
private List<String> cursorToListSearch(Cursor c){
//No element found
if (c.getCount() == 0)
return null;
List<String> searches = new ArrayList<>();
while (c.moveToNext() ) {
searches.add(c.getString(c.getColumnIndex(Sqlite.COL_KEYWORDS)));
}
//Close the cursor
c.close();
//Search list is returned
return searches;
}
}

View File

@ -26,7 +26,7 @@ import android.database.sqlite.SQLiteOpenHelper;
@SuppressWarnings("WeakerAccess")
public class Sqlite extends SQLiteOpenHelper {
public static final int DB_VERSION = 6;
public static final int DB_VERSION = 7;
public static final String DB_NAME = "mastodon_etalab_db";
public static SQLiteDatabase db;
private static Sqlite sInstance;
@ -40,6 +40,8 @@ public class Sqlite extends SQLiteOpenHelper {
static final String TABLE_STATUSES_STORED = "STATUSES_STORED";
//Table for custom emoji
static final String TABLE_CUSTOM_EMOJI = "CUSTOM_EMOJI";
//Table for search
static final String TABLE_SEARCH = "SEARCH";
public static final String COL_USER_ID = "USER_ID";
public static final String COL_USERNAME = "USERNAME";
@ -95,6 +97,12 @@ public class Sqlite extends SQLiteOpenHelper {
+ COL_SHORTCODE + " TEXT NOT NULL, " + COL_INSTANCE + " TEXT NOT NULL, "
+ COL_URL + " TEXT NOT NULL, " + COL_URL_STATIC + " TEXT NOT NULL, " + COL_DATE_CREATION + " TEXT NOT NULL)";
public static final String COL_KEYWORDS = "KEYWORDS";
private final String CREATE_TABLE_SEARCH = "CREATE TABLE " + TABLE_SEARCH + " ("
+ COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COL_KEYWORDS + " TEXT NOT NULL, " + COL_USER_ID + " TEXT NOT NULL, " + COL_DATE_CREATION + " TEXT NOT NULL)";
public Sqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@ -113,6 +121,7 @@ public class Sqlite extends SQLiteOpenHelper {
db.execSQL(CREATE_TABLE_USER_ACCOUNT);
db.execSQL(CREATE_TABLE_STATUSES_STORED);
db.execSQL(CREATE_TABLE_CUSTOM_EMOJI);
db.execSQL(CREATE_TABLE_SEARCH);
}
@Override
@ -132,6 +141,8 @@ public class Sqlite extends SQLiteOpenHelper {
+ COL_URL + " TEXT NOT NULL, " + COL_URL_STATIC + " TEXT NOT NULL, " + COL_DATE_CREATION + " TEXT NOT NULL)");
case 5:
db.execSQL("delete from "+ TABLE_CUSTOM_EMOJI); //Reset table due to bugs
case 6:
db.execSQL(CREATE_TABLE_SEARCH);
default:
break;
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

View File

@ -127,6 +127,15 @@
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_delete_floating"
tools:ignore="VectorDrawableCompat" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/add_new"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_action_add_new"
tools:ignore="VectorDrawableCompat" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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 <http://www.gnu.org/licenses>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/search_container"
android:divider="?android:dividerHorizontal"
android:showDividers="end"
android:paddingTop="5dp"
android:orientation="vertical">
<TextView
android:drawableRight="@drawable/ic_keyboard_arrow_right"
android:drawableEnd="@drawable/ic_keyboard_arrow_right"
android:id="@+id/search_keyword"
android:textSize="18sp"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:textStyle="bold"
android:layout_gravity="center"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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 <http://www.gnu.org/licenses>.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingLeft="@dimen/fab_margin"
android:paddingRight="@dimen/fab_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Listview drafts toots -->
<ListView
android:id="@+id/lv_search_toots"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
android:divider="@null"
>
</ListView>
<RelativeLayout
android:id="@+id/no_action"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/no_action_text"
android:padding="10dp"
android:layout_centerInParent="true"
android:gravity="center"
android:textSize="25sp"
android:layout_gravity="center"
android:textStyle="italic|bold"
android:typeface="serif"
android:text="@string/no_result"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
<!-- Main Loader -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loader"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/search_toot"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/action_search"
android:maxLines="1"
/>
</LinearLayout>

View File

@ -19,6 +19,10 @@
android:id="@+id/nav_drafts"
android:icon="@drawable/ic_save_white"
android:title="@string/drafts" />
<item
android:id="@+id/nav_search"
android:icon="@drawable/ic_search"
android:title="@string/search" />
<item
android:id="@+id/nav_remote_follow"
android:icon="@drawable/ic_person_add"

View File

@ -432,4 +432,6 @@
<string name="no_emoji">The app did not collect custom emojis for the moment.</string>
<string name="live_notif">Live notifications</string>
<string name="filter_regex">Mit regulären Ausdrücken filtern</string>
<string name="search">Suche</string>
<string name="delete">Löschen</string>
</resources>

View File

@ -439,4 +439,7 @@
<string name="no_emoji">L\'application n\'a pas encore collecté d\'emojis personnalisés</string>
<string name="live_notif">Notifications en direct</string>
<string name="filter_regex">Filtrer avec une expression rationnelle</string>
<string name="search">Rechercher</string>
<string name="delete">Supprimer</string>
</resources>

View File

@ -436,4 +436,6 @@
<string name="no_emoji">The app did not collect custom emojis for the moment.</string>
<string name="live_notif">Live notifications</string>
<string name="filter_regex">Wegfilteren met reguliere expressies</string>
<string name="search">Zoeken</string>
<string name="delete">Verwijderen</string>
</resources>

View File

@ -438,4 +438,6 @@
<string name="no_emoji">The app did not collect custom emojis for the moment.</string>
<string name="live_notif">Live notifications</string>
<string name="filter_regex">Filtrar com uma expressão regular</string>
<string name="search">Pesquisar</string>
<string name="delete">Eliminar</string>
</resources>

View File

@ -445,4 +445,6 @@
</string>
<string name="filter_regex">Filter out by regular expressions</string>
<string name="search">Search</string>
<string name="delete">Delete</string>
</resources>