Remote instance follow - step1
This commit is contained in:
parent
7df2c0b59e
commit
57d30a3f2e
|
@ -63,6 +63,12 @@
|
|||
android:name=".services.StreamingLocalTimelineService"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity android:name=".activities.InstanceFederatedActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:windowSoftInputMode = "adjustResize"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:theme="@style/AppThemeDark_NoActionBar"/>
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
|
|
|
@ -251,6 +251,16 @@ public abstract class BaseMainActivity extends BaseActivity
|
|||
iconGlobal.setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.dark_text), PorterDuff.Mode.SRC_IN);
|
||||
iconGlobal.setImageResource(R.drawable.ic_public);
|
||||
|
||||
FloatingActionButton federatedTimelines = findViewById(R.id.federated_timeline);
|
||||
|
||||
federatedTimelines.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(getApplicationContext(), InstanceFederatedActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
changeDrawableColor(getApplicationContext(), R.drawable.ic_home,R.color.dark_text);
|
||||
changeDrawableColor(getApplicationContext(), R.drawable.ic_notifications,R.color.dark_text);
|
||||
changeDrawableColor(getApplicationContext(), R.drawable.ic_people,R.color.dark_text);
|
||||
|
|
|
@ -0,0 +1,563 @@
|
|||
/* 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.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import fr.gouv.etalab.mastodon.R;
|
||||
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;
|
||||
import fr.gouv.etalab.mastodon.client.Entities.Account;
|
||||
import fr.gouv.etalab.mastodon.client.Entities.Status;
|
||||
import fr.gouv.etalab.mastodon.client.HttpsConnection;
|
||||
import fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment;
|
||||
import fr.gouv.etalab.mastodon.helper.Helper;
|
||||
import fr.gouv.etalab.mastodon.services.LiveNotificationService;
|
||||
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
|
||||
import fr.gouv.etalab.mastodon.sqlite.InstancesDAO;
|
||||
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
|
||||
import static fr.gouv.etalab.mastodon.helper.Helper.INSTANCE_NAME;
|
||||
import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION;
|
||||
import static fr.gouv.etalab.mastodon.helper.Helper.SEARCH_INSTANCE;
|
||||
import static fr.gouv.etalab.mastodon.helper.Helper.THEME_BLACK;
|
||||
|
||||
|
||||
public class InstanceFederatedActivity extends BaseActivity {
|
||||
|
||||
private FloatingActionButton add_new;
|
||||
public static String currentLocale;
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
private static BroadcastReceiver receive_data, receive_federated_data, receive_local_data;
|
||||
private String userIdService;
|
||||
private AppBarLayout appBar;
|
||||
private String userId;
|
||||
private String instance;
|
||||
private PagerAdapter adapter;
|
||||
boolean isLoadingInstance = false;
|
||||
private AutoCompleteTextView instance_list;
|
||||
private String oldSearch;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
|
||||
|
||||
|
||||
|
||||
final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
break;
|
||||
case Helper.THEME_BLACK:
|
||||
setTheme(R.style.AppThemeBlack_NoActionBar);
|
||||
break;
|
||||
default:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
}
|
||||
setContentView(R.layout.activity_federated);
|
||||
|
||||
|
||||
FloatingActionButton federated_timeline_close = findViewById(R.id.federated_timeline_close);
|
||||
|
||||
federated_timeline_close.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
FloatingActionButton add_new_instance = findViewById(R.id.add_new_instance);
|
||||
add_new_instance.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(InstanceFederatedActivity.this);
|
||||
LayoutInflater inflater = getLayoutInflater();
|
||||
@SuppressLint("InflateParams") View dialogView = inflater.inflate(R.layout.search_instance, null);
|
||||
dialogBuilder.setView(dialogView);
|
||||
|
||||
instance_list = dialogView.findViewById(R.id.search_instance);
|
||||
instance_list.setFilters(new InputFilter[]{new InputFilter.LengthFilter(60)});
|
||||
dialogBuilder.setPositiveButton(R.string.validate, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
|
||||
String instanceName = instance_list.getText().toString().trim();
|
||||
//Already in db
|
||||
List<String> s_ = new InstancesDAO(InstanceFederatedActivity.this, db).getInstanceByName(instanceName);
|
||||
if( s_ == null)
|
||||
s_ = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
new Thread(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
String response = new HttpsConnection(InstanceFederatedActivity.this).get("https://" + instanceName + "/api/v1/timelines/public?local=true", 10, null, null);
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
JSONObject resobj;
|
||||
try {
|
||||
new InstancesDAO(InstanceFederatedActivity.this, db).insertInstance(instanceName);
|
||||
|
||||
resobj = new JSONObject(response);
|
||||
Intent intent = new Intent(InstanceFederatedActivity.this, InstanceFederatedActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.putExtra(INTENT_ACTION, SEARCH_INSTANCE);
|
||||
intent.putExtra(INSTANCE_NAME, instanceName);
|
||||
startActivity(intent);
|
||||
} catch (JSONException ignored) {ignored.printStackTrace();}
|
||||
}
|
||||
});
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
Toast.makeText(getApplicationContext(), R.string.toast_instance_unavailable,Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialogInterface) {
|
||||
//Hide keyboard
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(instance_list.getWindowToken(), 0);
|
||||
}
|
||||
});
|
||||
if( alertDialog.getWindow() != null )
|
||||
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
alertDialog.show();
|
||||
|
||||
instance_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
|
||||
oldSearch = parent.getItemAtPosition(position).toString().trim();
|
||||
}
|
||||
});
|
||||
instance_list.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
Pattern host = Pattern.compile("([\\da-z\\.-]+\\.[a-z\\.]{2,12})");
|
||||
Matcher matcher = host.matcher(s.toString().trim());
|
||||
if( s.toString().trim().length() == 0 || !matcher.find()) {
|
||||
alertDialog.getButton(
|
||||
AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
} else {
|
||||
// Something into edit text. Enable the button.
|
||||
alertDialog.getButton(
|
||||
AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
||||
}
|
||||
if (s.length() > 2 && !isLoadingInstance) {
|
||||
final String action = "/instances/search";
|
||||
final HashMap<String, String> parameters = new HashMap<>();
|
||||
parameters.put("q", s.toString().trim());
|
||||
parameters.put("count", String.valueOf(50));
|
||||
parameters.put("name", String.valueOf(true));
|
||||
isLoadingInstance = true;
|
||||
|
||||
if( oldSearch == null || !oldSearch.equals(s.toString().trim()))
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final String response = new HttpsConnection(InstanceFederatedActivity.this).get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN);
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
isLoadingInstance = false;
|
||||
String[] instances;
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(response);
|
||||
JSONArray jsonArray = jsonObject.getJSONArray("instances");
|
||||
if (jsonArray != null) {
|
||||
int length = 0;
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
if( !jsonArray.getJSONObject(i).get("name").toString().contains("@"))
|
||||
length++;
|
||||
}
|
||||
instances = new String[length];
|
||||
int j = 0;
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
if( !jsonArray.getJSONObject(i).get("name").toString().contains("@")) {
|
||||
instances[j] = jsonArray.getJSONObject(i).get("name").toString();
|
||||
j++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instances = new String[]{};
|
||||
}
|
||||
instance_list.setAdapter(null);
|
||||
ArrayAdapter<String> adapter =
|
||||
new ArrayAdapter<>(InstanceFederatedActivity.this, android.R.layout.simple_list_item_1, instances);
|
||||
instance_list.setAdapter(adapter);
|
||||
if (instance_list.hasFocus() && !InstanceFederatedActivity.this.isFinishing())
|
||||
instance_list.showDropDown();
|
||||
oldSearch = s.toString().trim();
|
||||
|
||||
} catch (JSONException ignored) {
|
||||
isLoadingInstance = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (HttpsConnection.HttpsConnectionException e) {
|
||||
isLoadingInstance = false;
|
||||
} catch (Exception e) {
|
||||
isLoadingInstance = false;
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
else
|
||||
isLoadingInstance = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
//Test if user is still log in
|
||||
if( ! Helper.isLoggedIn(getApplicationContext())) {
|
||||
//It is not, the user is redirected to the login page
|
||||
Intent myIntent = new Intent(InstanceFederatedActivity.this, LoginActivity.class);
|
||||
startActivity(myIntent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
Helper.canPin = false;
|
||||
Helper.fillMapEmoji(getApplicationContext());
|
||||
//Here, the user is authenticated
|
||||
appBar = findViewById(R.id.appBar);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
if( theme == THEME_BLACK)
|
||||
toolbar.setBackgroundColor(ContextCompat.getColor(InstanceFederatedActivity.this, R.color.black));
|
||||
setSupportActionBar(toolbar);
|
||||
tabLayout = findViewById(R.id.tabLayout);
|
||||
|
||||
|
||||
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
|
||||
tabLayout.setTabMode(TabLayout.MODE_FIXED);
|
||||
|
||||
|
||||
|
||||
//Display filter for notification when long pressing the tab
|
||||
final LinearLayout tabStrip = (LinearLayout) tabLayout.getChildAt(0);
|
||||
|
||||
|
||||
viewPager = findViewById(R.id.viewpager);
|
||||
|
||||
adapter = new PagerAdapter
|
||||
(getSupportFragmentManager(), tabLayout.getTabCount());
|
||||
viewPager.setAdapter(adapter);
|
||||
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
|
||||
|
||||
|
||||
|
||||
|
||||
refreshInstanceTab();
|
||||
|
||||
//Hide the default title
|
||||
if( getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayShowTitleEnabled(false);
|
||||
getSupportActionBar().getThemedContext().setTheme(R.style.AppThemeBlack);
|
||||
}
|
||||
//Defines the current locale of the device in a static variable
|
||||
currentLocale = Helper.currentLocale(getApplicationContext());
|
||||
|
||||
|
||||
add_new = findViewById(R.id.add_new);
|
||||
|
||||
|
||||
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
instance = sharedpreferences.getString(Helper.PREF_INSTANCE, Helper.getLiveInstance(getApplicationContext()));
|
||||
|
||||
Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(userId);
|
||||
if( account == null){
|
||||
Helper.logout(getApplicationContext());
|
||||
Intent myIntent = new Intent(InstanceFederatedActivity.this, LoginActivity.class);
|
||||
startActivity(myIntent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ImageView iconbar = toolbar.findViewById(R.id.iconbar);
|
||||
|
||||
Helper.loadPictureIcon(InstanceFederatedActivity.this, account.getAvatar(),iconbar);
|
||||
|
||||
|
||||
|
||||
|
||||
if( receive_data != null)
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data);
|
||||
receive_data = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Bundle b = intent.getExtras();
|
||||
Helper.EventStreaming eventStreaming = (Helper.EventStreaming) intent.getSerializableExtra("eventStreaming");
|
||||
assert b != null;
|
||||
userIdService = b.getString("userIdService", null);
|
||||
if( userIdService != null && userIdService.equals(userId)) {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
mamageNewIntent(getIntent());
|
||||
// LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA));
|
||||
}
|
||||
|
||||
public void refreshInstanceTab(){
|
||||
Helper.addInstanceTab(InstanceFederatedActivity.this, tabLayout, adapter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume(){
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
mamageNewIntent(intent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Manages new intents
|
||||
* @param intent Intent - intent related to a notification in top bar
|
||||
*/
|
||||
private void mamageNewIntent(Intent intent){
|
||||
if( intent == null || intent.getExtras() == null )
|
||||
return;
|
||||
Bundle extras = intent.getExtras();
|
||||
if( extras.containsKey(INTENT_ACTION) ){
|
||||
if(extras.getInt(INTENT_ACTION) == SEARCH_INSTANCE){
|
||||
String instanceName = extras.getString(INSTANCE_NAME);
|
||||
if( instanceName != null){
|
||||
adapter = new InstanceFederatedActivity.PagerAdapter
|
||||
(getSupportFragmentManager(), tabLayout.getTabCount());
|
||||
viewPager.setAdapter(adapter);
|
||||
for(int i = 0; i < tabLayout.getTabCount() ; i++ ){
|
||||
if( tabLayout.getTabAt(i).getText() != null && tabLayout.getTabAt(i).getText().equals(instanceName.trim())){
|
||||
tabLayout.getTabAt(i).select();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
intent.replaceExtras(new Bundle());
|
||||
intent.setAction("");
|
||||
intent.setData(null);
|
||||
intent.setFlags(0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStart(){
|
||||
super.onStart();
|
||||
if( receive_federated_data != null)
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_federated_data);
|
||||
receive_federated_data = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Bundle b = intent.getExtras();
|
||||
assert b != null;
|
||||
userIdService = b.getString("userIdService", null);
|
||||
if( userIdService != null && userIdService.equals(userId)) {
|
||||
Status status = b.getParcelable("data");
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(receive_federated_data, new IntentFilter(Helper.RECEIVE_FEDERATED_DATA));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop(){
|
||||
super.onStop();
|
||||
if( receive_federated_data != null)
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_federated_data);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(){
|
||||
super.onDestroy();
|
||||
if( receive_data != null)
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Page Adapter for settings
|
||||
*/
|
||||
public class PagerAdapter extends FragmentStatePagerAdapter {
|
||||
int mNumOfTabs;
|
||||
|
||||
private PagerAdapter(FragmentManager fm, int NumOfTabs) {
|
||||
super(fm);
|
||||
this.mNumOfTabs = NumOfTabs;
|
||||
}
|
||||
|
||||
public void removeTabPage() {
|
||||
this.mNumOfTabs--;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addTabPage(String title) {
|
||||
TabLayout.Tab tab = tabLayout.newTab();
|
||||
tab.setText(title);
|
||||
this.mNumOfTabs++;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
//Selection comes from another menu, no action to do
|
||||
DisplayStatusFragment statusFragment;
|
||||
Bundle bundle = new Bundle();
|
||||
statusFragment = new DisplayStatusFragment();
|
||||
bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE);
|
||||
bundle.putString("remote_instance", tabLayout.getTabAt(position).getText().toString());
|
||||
statusFragment.setArguments(bundle);
|
||||
return statusFragment;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mNumOfTabs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public void updateTimeLine(RetrieveFeedsAsyncTask.Type type, int value){
|
||||
int position = tabLayout.getSelectedTabPosition();
|
||||
View tabLocal = tabLayout.getTabAt(position).getCustomView();
|
||||
assert tabLocal != null;
|
||||
TextView tabCounter = tabLocal.findViewById(R.id.tab_counter);
|
||||
tabCounter.setText(String.valueOf(value));
|
||||
if( value > 0){
|
||||
tabCounter.setVisibility(View.VISIBLE);
|
||||
}else {
|
||||
tabCounter.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void startSreaming(){
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
boolean liveNotifications = sharedpreferences.getBoolean(Helper.SET_LIVE_NOTIFICATIONS, true);
|
||||
if( liveNotifications) {
|
||||
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
assert manager != null;
|
||||
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (LiveNotificationService.class.getName().equals(service.service.getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Intent streamingIntent = new Intent(this, LiveNotificationService.class);
|
||||
startService(streamingIntent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -34,6 +34,7 @@ import android.text.util.Linkify;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Button;
|
||||
|
@ -72,6 +73,7 @@ public class LoginActivity extends BaseActivity {
|
|||
private EditText login_uid;
|
||||
private EditText login_passwd;
|
||||
boolean isLoadingInstance = false;
|
||||
private String oldSearch;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -141,6 +143,12 @@ public class LoginActivity extends BaseActivity {
|
|||
if (theme == Helper.THEME_LIGHT) {
|
||||
connectionButton.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
|
||||
}
|
||||
login_instance.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
|
||||
oldSearch = parent.getItemAtPosition(position).toString().trim();
|
||||
}
|
||||
});
|
||||
login_instance.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
@ -157,9 +165,10 @@ public class LoginActivity extends BaseActivity {
|
|||
final String action = "/instances/search";
|
||||
final HashMap<String, String> parameters = new HashMap<>();
|
||||
parameters.put("q", s.toString().trim());
|
||||
parameters.put("count", String.valueOf(5));
|
||||
parameters.put("count", String.valueOf(50));
|
||||
parameters.put("name", String.valueOf(true));
|
||||
isLoadingInstance = true;
|
||||
if( oldSearch == null || !oldSearch.equals(s.toString().trim()))
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -173,9 +182,18 @@ public class LoginActivity extends BaseActivity {
|
|||
JSONObject jsonObject = new JSONObject(response);
|
||||
JSONArray jsonArray = jsonObject.getJSONArray("instances");
|
||||
if (jsonArray != null) {
|
||||
instances = new String[jsonArray.length()];
|
||||
int length = 0;
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
instances[i] = jsonArray.getJSONObject(i).get("name").toString();
|
||||
if( !jsonArray.getJSONObject(i).get("name").toString().contains("@"))
|
||||
length++;
|
||||
}
|
||||
instances = new String[length];
|
||||
int j = 0;
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
if( !jsonArray.getJSONObject(i).get("name").toString().contains("@")) {
|
||||
instances[j] = jsonArray.getJSONObject(i).get("name").toString();
|
||||
j++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instances = new String[]{};
|
||||
|
@ -186,6 +204,7 @@ public class LoginActivity extends BaseActivity {
|
|||
login_instance.setAdapter(adapter);
|
||||
if (login_instance.hasFocus() && !LoginActivity.this.isFinishing())
|
||||
login_instance.showDropDown();
|
||||
oldSearch = s.toString().trim();
|
||||
|
||||
} catch (JSONException ignored) {
|
||||
isLoadingInstance = false;
|
||||
|
|
|
@ -47,6 +47,7 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
|
|||
private boolean showPinned = false;
|
||||
private WeakReference<Context> contextReference;
|
||||
private FilterToots filterToots;
|
||||
private String instanceName;
|
||||
|
||||
public enum Type{
|
||||
HOME,
|
||||
|
@ -60,7 +61,8 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
|
|||
CONTEXT,
|
||||
TAG,
|
||||
CACHE_BOOKMARKS,
|
||||
CACHE_STATUS
|
||||
CACHE_STATUS,
|
||||
REMOTE_INSTANCE
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,6 +81,14 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
|
|||
this.listener = onRetrieveFeedsInterface;
|
||||
}
|
||||
|
||||
public RetrieveFeedsAsyncTask(Context context, Type action, String instanceName, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
|
||||
this.contextReference = new WeakReference<>(context);
|
||||
this.action = action;
|
||||
this.max_id = max_id;
|
||||
this.listener = onRetrieveFeedsInterface;
|
||||
this.instanceName = instanceName;
|
||||
}
|
||||
|
||||
public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, boolean showPinned, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
|
||||
this.contextReference = new WeakReference<>(context);
|
||||
this.action = action;
|
||||
|
@ -111,6 +121,9 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
|
|||
case PUBLIC:
|
||||
apiResponse = api.getPublicTimeline(false, max_id);
|
||||
break;
|
||||
case REMOTE_INSTANCE:
|
||||
apiResponse = api.getPublicTimeline(this.instanceName,false, max_id);
|
||||
break;
|
||||
case FAVOURITES:
|
||||
apiResponse = api.getFavourites(max_id);
|
||||
break;
|
||||
|
|
|
@ -16,6 +16,7 @@ package fr.gouv.etalab.mastodon.client;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
@ -530,6 +531,16 @@ public class API {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves public timeline for the account *synchronously*
|
||||
* @param local boolean only local timeline
|
||||
* @param max_id String id max
|
||||
* @return APIResponse
|
||||
*/
|
||||
public APIResponse getPublicTimeline(String instanceName, boolean local, String max_id){
|
||||
return getPublicTimeline(local, instanceName, max_id, null, tootPerPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves public timeline for the account *synchronously*
|
||||
* @param local boolean only local timeline
|
||||
|
@ -537,7 +548,7 @@ public class API {
|
|||
* @return APIResponse
|
||||
*/
|
||||
public APIResponse getPublicTimeline(boolean local, String max_id){
|
||||
return getPublicTimeline(local, max_id, null, tootPerPage);
|
||||
return getPublicTimeline(local, null, max_id, null, tootPerPage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -547,7 +558,7 @@ public class API {
|
|||
* @return APIResponse
|
||||
*/
|
||||
public APIResponse getPublicTimelineSinceId(boolean local, String since_id) {
|
||||
return getPublicTimeline(local, null, since_id, tootPerPage);
|
||||
return getPublicTimeline(local, null, null, since_id, tootPerPage);
|
||||
}
|
||||
|
||||
|
||||
|
@ -560,7 +571,7 @@ public class API {
|
|||
* @param limit int limit - max value 40
|
||||
* @return APIResponse
|
||||
*/
|
||||
private APIResponse getPublicTimeline(boolean local, String max_id, String since_id, int limit){
|
||||
private APIResponse getPublicTimeline(boolean local, String instanceName, String max_id, String since_id, int limit){
|
||||
|
||||
HashMap<String, String> params = new HashMap<>();
|
||||
if( local)
|
||||
|
@ -575,7 +586,12 @@ public class API {
|
|||
statuses = new ArrayList<>();
|
||||
try {
|
||||
HttpsConnection httpsConnection = new HttpsConnection(context);
|
||||
String response = httpsConnection.get(getAbsoluteUrl("/timelines/public"), 60, params, prefKeyOauthTokenT);
|
||||
String url;
|
||||
if( instanceName == null)
|
||||
url = getAbsoluteUrl("/timelines/public");
|
||||
else
|
||||
url = getAbsoluteUrlRemoteInstance(instanceName);
|
||||
String response = httpsConnection.get(url, 60, params, prefKeyOauthTokenT);
|
||||
apiResponse.setSince_id(httpsConnection.getSince_id());
|
||||
apiResponse.setMax_id(httpsConnection.getMax_id());
|
||||
statuses = parseStatuses(new JSONArray(response));
|
||||
|
@ -2291,4 +2307,7 @@ public class API {
|
|||
}
|
||||
|
||||
|
||||
private String getAbsoluteUrlRemoteInstance(String instanceName) {
|
||||
return "https://" + instanceName + "/api/v1/timelines/public?local=true";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
|
|||
private String userId, instance;
|
||||
private SharedPreferences sharedpreferences;
|
||||
private boolean isSwipped;
|
||||
private String remoteInstance;
|
||||
|
||||
public DisplayStatusFragment(){
|
||||
}
|
||||
|
@ -101,6 +102,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
|
|||
tag = bundle.getString("tag", null);
|
||||
showMediaOnly = bundle.getBoolean("showMediaOnly",false);
|
||||
showPinned = bundle.getBoolean("showPinned",false);
|
||||
remoteInstance = bundle.getString("remote_instance", "");
|
||||
}
|
||||
isSwipped = false;
|
||||
max_id = null;
|
||||
|
@ -151,6 +153,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
|
|||
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if( type == RetrieveFeedsAsyncTask.Type.TAG)
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if( remoteInstance != null)
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, remoteInstance, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
|
@ -208,6 +212,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
|
|||
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if (type == RetrieveFeedsAsyncTask.Type.TAG)
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if( remoteInstance != null)
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, remoteInstance, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else {
|
||||
if( type == RetrieveFeedsAsyncTask.Type.HOME ){
|
||||
String bookmark;
|
||||
|
@ -230,6 +236,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
|
|||
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if (type == RetrieveFeedsAsyncTask.Type.TAG)
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else if( remoteInstance != null)
|
||||
asyncTask = new RetrieveFeedsAsyncTask(context, type, remoteInstance, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else {
|
||||
if( type == RetrieveFeedsAsyncTask.Type.HOME ){
|
||||
String bookmark;
|
||||
|
@ -397,7 +405,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
|
|||
}
|
||||
|
||||
|
||||
} else if (type == RetrieveFeedsAsyncTask.Type.PUBLIC || type == RetrieveFeedsAsyncTask.Type.LOCAL) {
|
||||
} else if (type == RetrieveFeedsAsyncTask.Type.PUBLIC || type == RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE) {
|
||||
|
||||
status.setReplies(new ArrayList<Status>());
|
||||
status.setNew(false);
|
||||
|
|
|
@ -142,6 +142,7 @@ import fr.gouv.etalab.mastodon.BuildConfig;
|
|||
import fr.gouv.etalab.mastodon.R;
|
||||
import fr.gouv.etalab.mastodon.activities.BaseMainActivity;
|
||||
import fr.gouv.etalab.mastodon.activities.HashTagActivity;
|
||||
import fr.gouv.etalab.mastodon.activities.InstanceFederatedActivity;
|
||||
import fr.gouv.etalab.mastodon.activities.LoginActivity;
|
||||
import fr.gouv.etalab.mastodon.activities.MainActivity;
|
||||
import fr.gouv.etalab.mastodon.activities.ShowAccountActivity;
|
||||
|
@ -158,6 +159,7 @@ import fr.gouv.etalab.mastodon.client.Entities.Status;
|
|||
import fr.gouv.etalab.mastodon.client.Entities.Tag;
|
||||
import fr.gouv.etalab.mastodon.client.Entities.Version;
|
||||
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
|
||||
import fr.gouv.etalab.mastodon.sqlite.InstancesDAO;
|
||||
import fr.gouv.etalab.mastodon.sqlite.SearchDAO;
|
||||
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
|
||||
|
||||
|
@ -213,6 +215,7 @@ public class Helper {
|
|||
public static final String SHOULD_CONTINUE_STREAMING_LOCAL = "should_continue_streaming_local";
|
||||
public static final String SEARCH_KEYWORD = "search_keyword";
|
||||
public static final String CLIP_BOARD = "clipboard";
|
||||
public static final String INSTANCE_NAME = "instance_name";
|
||||
//Notifications
|
||||
public static final int NOTIFICATION_INTENT = 1;
|
||||
public static final int HOME_TIMELINE_INTENT = 2;
|
||||
|
@ -221,6 +224,8 @@ public class Helper {
|
|||
public static final int ADD_USER_INTENT = 5;
|
||||
public static final int BACKUP_INTENT = 6;
|
||||
public static final int SEARCH_TAG = 7;
|
||||
public static final int SEARCH_INSTANCE = 8;
|
||||
|
||||
//Settings
|
||||
public static final String SET_TOOTS_PER_PAGE = "set_toots_per_page";
|
||||
public static final String SET_ACCOUNTS_PER_PAGE = "set_accounts_per_page";
|
||||
|
@ -2162,6 +2167,54 @@ public class Helper {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public static void addInstanceTab(Context context, TabLayout tableLayout, InstanceFederatedActivity.PagerAdapter pagerAdapter){
|
||||
SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
new InstancesDAO(context, db).cleanDoublon();
|
||||
List<String> instances = new InstancesDAO(context, db).getAllInstances();
|
||||
int allTabCount = tableLayout.getTabCount();
|
||||
while(allTabCount > 0){
|
||||
removeTab(tableLayout, pagerAdapter, allTabCount-1);
|
||||
allTabCount -=1;
|
||||
}
|
||||
if( instances != null) {
|
||||
for (String instance : instances) {
|
||||
addTab(tableLayout, pagerAdapter, instance);
|
||||
}
|
||||
if( instances.size() > 0 ){
|
||||
tableLayout.setTabGravity(TabLayout.GRAVITY_FILL);
|
||||
tableLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeSearchTab(String keyword, TabLayout tableLayout, InstanceFederatedActivity.PagerAdapter pagerAdapter){
|
||||
|
||||
int selection = -1;
|
||||
for(int i = 0; i < tableLayout.getTabCount() ; i++ ){
|
||||
if( tableLayout.getTabAt(i).getText() != null && tableLayout.getTabAt(i).getText().equals(keyword)) {
|
||||
selection = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( selection != -1)
|
||||
removeTab(tableLayout, pagerAdapter, selection);
|
||||
}
|
||||
|
||||
private static void removeTab(TabLayout tableLayout, InstanceFederatedActivity.PagerAdapter pagerAdapter, int position) {
|
||||
if (tableLayout.getTabCount() >= position) {
|
||||
tableLayout.removeTabAt(position);
|
||||
pagerAdapter.removeTabPage();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTab(TabLayout tableLayout, InstanceFederatedActivity.PagerAdapter pagerAdapter, String title) {
|
||||
tableLayout.addTab(tableLayout.newTab().setText(title));
|
||||
pagerAdapter.addTabPage(title);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void addSearchTag(Context context, TabLayout tableLayout, BaseMainActivity.PagerAdapter pagerAdapter){
|
||||
SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
List<String> searches = new SearchDAO(context, db).getAllSearch();
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
package fr.gouv.etalab.mastodon.sqlite;
|
||||
/* Copyright 2018 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 20/08/2018.
|
||||
* Manage instance names in DB
|
||||
*/
|
||||
public class InstancesDAO {
|
||||
|
||||
private SQLiteDatabase db;
|
||||
public Context context;
|
||||
private String userId;
|
||||
|
||||
public InstancesDAO(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 an instance name in database
|
||||
* @param instanceName String
|
||||
*/
|
||||
public void insertInstance(String instanceName) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Sqlite.COL_INSTANCE, instanceName);
|
||||
values.put(Sqlite.COL_USER_ID, userId);
|
||||
values.put(Sqlite.COL_DATE_CREATION, Helper.dateToString(new Date()));
|
||||
//Inserts search
|
||||
try{
|
||||
db.insert(Sqlite.TABLE_INSTANCES, null, values);
|
||||
}catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
|
||||
//------- REMOVE -------
|
||||
|
||||
/***
|
||||
* Remove instance by its name
|
||||
* @return int
|
||||
*/
|
||||
public int remove(String instanceName){
|
||||
return db.delete(Sqlite.TABLE_INSTANCES, Sqlite.COL_INSTANCE + " = \"" + instanceName + "\" AND " + Sqlite.COL_USER_ID + " = \"" + userId+ "\"", null);
|
||||
}
|
||||
|
||||
//------- REMOVE -------
|
||||
|
||||
/***
|
||||
* Remove instance by its name
|
||||
* @return int
|
||||
*/
|
||||
public int cleanDoublon(){
|
||||
return db.delete(Sqlite.TABLE_INSTANCES, Sqlite.COL_ID + " NOT IN (" +
|
||||
" SELECT MIN("+Sqlite.COL_ID+")" +
|
||||
" FROM " + Sqlite.TABLE_INSTANCES +
|
||||
" GROUP BY "+ Sqlite.COL_INSTANCE + "," + Sqlite.COL_USER_ID +")", null);
|
||||
}
|
||||
|
||||
//------- GETTERS -------
|
||||
|
||||
/**
|
||||
* Returns all instances in db for a user
|
||||
* @return instances List<String>
|
||||
*/
|
||||
public List<String> getAllInstances(){
|
||||
try {
|
||||
Cursor c = db.query(Sqlite.TABLE_INSTANCES, null, Sqlite.COL_USER_ID + " = '" + userId+ "'", null, null, null, Sqlite.COL_INSTANCE + " ASC", null);
|
||||
return cursorToListSearch(c);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns instance by its nale in db
|
||||
* @return instance List<String>
|
||||
*/
|
||||
public List<String> getInstanceByName(String keyword){
|
||||
try {
|
||||
Cursor c = db.query(Sqlite.TABLE_INSTANCES, null, Sqlite.COL_INSTANCE + " = \"" + keyword + "\" AND " + Sqlite.COL_USER_ID + " = \"" + userId+ "\"", null, null, null, null, null);
|
||||
return cursorToListSearch(c);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Method to hydrate stored instances 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> instances = new ArrayList<>();
|
||||
while (c.moveToNext() ) {
|
||||
instances.add(c.getString(c.getColumnIndex(Sqlite.COL_INSTANCE)));
|
||||
}
|
||||
//Close the cursor
|
||||
c.close();
|
||||
//Search list is returned
|
||||
return instances;
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
|||
|
||||
public class Sqlite extends SQLiteOpenHelper {
|
||||
|
||||
public static final int DB_VERSION = 11;
|
||||
public static final int DB_VERSION = 12;
|
||||
public static final String DB_NAME = "mastodon_etalab_db";
|
||||
public static SQLiteDatabase db;
|
||||
private static Sqlite sInstance;
|
||||
|
@ -49,6 +49,8 @@ public class Sqlite extends SQLiteOpenHelper {
|
|||
//Table for cached statuses
|
||||
static final String TABLE_STATUSES_CACHE = "STATUSES_CACHE";
|
||||
|
||||
//Table for instance names
|
||||
static final String TABLE_INSTANCES = "INSTANCES";
|
||||
|
||||
static final String COL_USER_ID = "USER_ID";
|
||||
static final String COL_USERNAME = "USERNAME";
|
||||
|
@ -159,6 +161,11 @@ public class Sqlite extends SQLiteOpenHelper {
|
|||
+ TABLE_STATUSES_CACHE + "(" + COL_INSTANCE +"," + COL_STATUS_ID + ")";
|
||||
|
||||
|
||||
private final String CREATE_TABLE_INSTANCES = "CREATE TABLE " + TABLE_INSTANCES + " ("
|
||||
+ COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ COL_INSTANCE + " 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);
|
||||
}
|
||||
|
@ -181,6 +188,7 @@ public class Sqlite extends SQLiteOpenHelper {
|
|||
db.execSQL(CREATE_TABLE_TEMP_MUTE);
|
||||
db.execSQL(CREATE_TABLE_STATUSES_CACHE);
|
||||
db.execSQL(CREATE_UNIQUE_CACHE_INDEX);
|
||||
db.execSQL(CREATE_TABLE_INSTANCES);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -214,6 +222,8 @@ public class Sqlite extends SQLiteOpenHelper {
|
|||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_STATUSES_CACHE);
|
||||
db.execSQL(CREATE_TABLE_STATUSES_CACHE);
|
||||
db.execSQL(CREATE_UNIQUE_CACHE_INDEX);
|
||||
case 11:
|
||||
db.execSQL(CREATE_TABLE_INSTANCES);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 464 B |
Binary file not shown.
After Width: | Height: | Size: 377 B |
Binary file not shown.
After Width: | Height: | Size: 315 B |
Binary file not shown.
After Width: | Height: | Size: 557 B |
Binary file not shown.
After Width: | Height: | Size: 847 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2018 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>
|
||||
-->
|
||||
<android.support.v4.widget.DrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:openDrawer="start">
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="fr.gouv.etalab.mastodon.activities.MainActivity">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay"
|
||||
>
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
android:theme="@style/AppThemeDark_NoActionBar"
|
||||
app:popupTheme="?attr/popupOverlay">
|
||||
<ImageView
|
||||
android:id="@+id/iconbar"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
<LinearLayout
|
||||
android:id="@+id/toolbar_search_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:orientation="horizontal">
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabSelectedTextColor="?attr/colorAccent"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.Toolbar>
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
|
||||
<!-- Framelayout to display Fragments -->
|
||||
<android.support.v4.view.ViewPager
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/viewpager"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:context="fr.gouv.etalab.mastodon.activities.MainActivity"
|
||||
>
|
||||
</android.support.v4.view.ViewPager>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/add_new_instance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/fab_margin_floating"
|
||||
app:srcCompat="@drawable/ic_action_add_new"
|
||||
tools:ignore="VectorDrawableCompat" />
|
||||
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/federated_timeline_close"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="bottom|start"
|
||||
app:fabSize="mini"
|
||||
app:srcCompat="@drawable/ic_close"
|
||||
android:layout_margin="@dimen/fab_margin_floating"
|
||||
tools:ignore="VectorDrawableCompat" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
|
@ -136,6 +136,16 @@
|
|||
android:layout_margin="@dimen/fab_margin_floating"
|
||||
app:srcCompat="@drawable/ic_action_add_new"
|
||||
tools:ignore="VectorDrawableCompat" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/federated_timeline"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
app:fabSize="mini"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:layout_margin="@dimen/fab_margin_floating"
|
||||
app:srcCompat="@drawable/ic_public_world"
|
||||
tools:ignore="VectorDrawableCompat" />
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<android.support.design.widget.NavigationView
|
||||
|
|
|
@ -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">
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/search_instance"
|
||||
android:inputType="text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/instance"
|
||||
android:maxLines="1"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -544,6 +544,7 @@
|
|||
<string name="support_the_app_on_liberapay">Support the app on Liberapay</string>
|
||||
<string name="alert_regex">There is an error in the regular expression!</string>
|
||||
<string name="no_account_yet">No account yet?</string>
|
||||
<string name="toast_instance_unavailable">No timelines was found on this instance!</string>
|
||||
<string-array translatable="false" name="proxy_type_choice">
|
||||
<item>HTTP</item>
|
||||
<item>SOCKS</item>
|
||||
|
|
Loading…
Reference in New Issue