Merged tom79/mastodon_etalab into master

This commit is contained in:
PhotonQyv 2017-09-10 17:46:11 +01:00
commit 00ccdc42c9
106 changed files with 3650 additions and 1185 deletions

BIN
app/app-fdroid-release.apk Normal file

Binary file not shown.

View File

@ -7,8 +7,8 @@ android {
applicationId "fr.gouv.etalab.mastodon" applicationId "fr.gouv.etalab.mastodon"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 25 targetSdkVersion 25
versionCode 48 versionCode 49
versionName "1.4.8" versionName "1.4.9-beta-1"
} }
buildTypes { buildTypes {
release { release {

View File

@ -15,26 +15,31 @@
package fr.gouv.etalab.mastodon.activities; package fr.gouv.etalab.mastodon.activities;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.support.v7.widget.SwitchCompat; import android.support.v7.widget.SwitchCompat;
import android.util.Log;
import android.util.Patterns;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView;
@ -61,12 +66,13 @@ import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Stack; import java.util.Stack;
import java.util.concurrent.TimeUnit; import java.util.regex.Matcher;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveMetaDataAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoByIDAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoByIDAsyncTask;
import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
@ -75,7 +81,9 @@ import fr.gouv.etalab.mastodon.fragments.DisplayFollowRequestSentFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayScheduledTootsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayScheduledTootsFragment;
import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMetaDataInterface;
import fr.gouv.etalab.mastodon.interfaces.OnUpdateAccountInfoInterface; import fr.gouv.etalab.mastodon.interfaces.OnUpdateAccountInfoInterface;
import fr.gouv.etalab.mastodon.services.StreamingService;
import fr.gouv.etalab.mastodon.sqlite.Sqlite; import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountsAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;
@ -100,7 +108,7 @@ import android.support.v4.app.FragmentStatePagerAdapter;
public class MainActivity extends AppCompatActivity public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, OnUpdateAccountInfoInterface { implements NavigationView.OnNavigationItemSelectedListener, OnUpdateAccountInfoInterface, OnRetrieveMetaDataInterface {
private FloatingActionButton toot; private FloatingActionButton toot;
private HashMap<String, String> tagTile = new HashMap<>(); private HashMap<String, String> tagTile = new HashMap<>();
@ -119,7 +127,8 @@ public class MainActivity extends AppCompatActivity
private DisplayStatusFragment homeFragment; private DisplayStatusFragment homeFragment;
private DisplayNotificationsFragment notificationsFragment; private DisplayNotificationsFragment notificationsFragment;
private BroadcastReceiver receive_data;
private boolean display_local, display_global;
public MainActivity() { public MainActivity() {
} }
@ -127,7 +136,47 @@ public class MainActivity extends AppCompatActivity
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
receive_data = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
StreamingService.EventStreaming eventStreaming = (StreamingService.EventStreaming) intent.getSerializableExtra("eventStreaming");
if( eventStreaming == StreamingService.EventStreaming.NOTIFICATION){
if(notificationsFragment != null){
if(notificationsFragment.getUserVisibleHint() && isActivityVisible()){
notificationsFragment.showNewContent();
}else{
notificationsFragment.refresh();
}
}
}else if(eventStreaming == StreamingService.EventStreaming.UPDATE){
if( homeFragment != null){
if(homeFragment.getUserVisibleHint() && isActivityVisible()){
homeFragment.showNewContent();
}else{
homeFragment.refresh();
}
}
}else if(eventStreaming == StreamingService.EventStreaming.DELETE){
String id = b.getString("id");
if(notificationsFragment != null) {
if (notificationsFragment.getUserVisibleHint()) {
} else {
}
}
}
updateNotifCounter();
updateHomeCounter();
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA));
final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_LIGHT){ if( theme == Helper.THEME_LIGHT){
@ -137,6 +186,9 @@ public class MainActivity extends AppCompatActivity
} }
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
display_local = sharedpreferences.getBoolean(Helper.SET_DISPLAY_LOCAL, true);
display_global = sharedpreferences.getBoolean(Helper.SET_DISPLAY_GLOBAL, true);
//Test if user is still log in //Test if user is still log in
if( ! Helper.isLoggedIn(getApplicationContext())) { if( ! Helper.isLoggedIn(getApplicationContext())) {
//It is not, the user is redirected to the login page //It is not, the user is redirected to the login page
@ -145,7 +197,16 @@ public class MainActivity extends AppCompatActivity
finish(); finish();
return; return;
} }
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
List<Account> accounts = new AccountDAO(getApplicationContext(), db).getAllAccount();
if( accounts != null){
for (Account account: accounts) {
Intent intent = new Intent(getApplicationContext(), StreamingService.class);
intent.putExtra("accountId", account.getId());
intent.putExtra("accountAcct", account.getAcct());
startService(intent);
}
}
Helper.fillMapEmoji(getApplicationContext()); Helper.fillMapEmoji(getApplicationContext());
//Here, the user is authenticated //Here, the user is authenticated
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
@ -194,8 +255,10 @@ public class MainActivity extends AppCompatActivity
tabLayout.addTab(tabHome); tabLayout.addTab(tabHome);
tabLayout.addTab(tabNotif); tabLayout.addTab(tabNotif);
tabLayout.addTab(tabLocal); if( display_local)
tabLayout.addTab(tabPublic); tabLayout.addTab(tabLocal);
if( display_global)
tabLayout.addTab(tabPublic);
viewPager = (ViewPager) findViewById(R.id.viewpager); viewPager = (ViewPager) findViewById(R.id.viewpager);
main_app_container = (RelativeLayout) findViewById(R.id.main_app_container); main_app_container = (RelativeLayout) findViewById(R.id.main_app_container);
@ -203,7 +266,6 @@ public class MainActivity extends AppCompatActivity
(getSupportFragmentManager(), tabLayout.getTabCount()); (getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter); viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
final boolean bubbles = sharedpreferences.getBoolean(Helper.SET_BUBBLE_COUNTER, true);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override @Override
public void onTabSelected(TabLayout.Tab tab) { public void onTabSelected(TabLayout.Tab tab) {
@ -222,29 +284,32 @@ public class MainActivity extends AppCompatActivity
main_app_container.setVisibility(View.GONE); main_app_container.setVisibility(View.GONE);
viewPager.setVisibility(View.VISIBLE); viewPager.setVisibility(View.VISIBLE);
Helper.switchLayout(MainActivity.this); Helper.switchLayout(MainActivity.this);
switch (tab.getPosition()){ if( tab.getPosition() == 0) {
case 0: item = navigationView.getMenu().findItem(R.id.nav_home);
item = navigationView.getMenu().findItem(R.id.nav_home); fragmentTag = "HOME_TIMELINE";
fragmentTag = "HOME_TIMELINE"; if (homeFragment != null && Helper.getUnreadToots(getApplicationContext(), null) > 0) {
if( bubbles && homeFragment != null) homeFragment.refresh();
homeFragment.refreshData(); }
updateHomeCounter(0); Helper.cacheStatusClear(getApplicationContext(), null);
break; updateHomeCounter();
case 1: }else if( tab.getPosition() == 1) {
fragmentTag = "NOTIFICATIONS"; fragmentTag = "NOTIFICATIONS";
item = navigationView.getMenu().findItem(R.id.nav_notification); item = navigationView.getMenu().findItem(R.id.nav_notification);
updateNotifCounter(0); if (notificationsFragment != null && Helper.getUnreadNotifications(getApplicationContext(), null) > 0) {
if( bubbles && notificationsFragment != null) notificationsFragment.refresh();
notificationsFragment.refreshData(); }
break; Helper.cacheNotificationsClear(getApplicationContext(), null);
case 2: updateNotifCounter();
fragmentTag = "LOCAL_TIMELINE"; }else if( tab.getPosition() == 2 && display_local) {
item = navigationView.getMenu().findItem(R.id.nav_local);
break; fragmentTag = "LOCAL_TIMELINE";
case 3: item = navigationView.getMenu().findItem(R.id.nav_local);
}else if( tab.getPosition() == 2 && !display_local) {
item = navigationView.getMenu().findItem(R.id.nav_global); item = navigationView.getMenu().findItem(R.id.nav_global);
fragmentTag = "PUBLIC_TIMELINE"; fragmentTag = "PUBLIC_TIMELINE";
break; }else if( tab.getPosition() == 3){
item = navigationView.getMenu().findItem(R.id.nav_global);
fragmentTag = "PUBLIC_TIMELINE";
} }
if( item != null){ if( item != null){
toolbarTitle.setText(item.getTitle()); toolbarTitle.setText(item.getTitle());
@ -281,9 +346,15 @@ public class MainActivity extends AppCompatActivity
Fragment fragment = (Fragment) viewPager.getAdapter().instantiateItem(viewPager, tab.getPosition()); Fragment fragment = (Fragment) viewPager.getAdapter().instantiateItem(viewPager, tab.getPosition());
switch (tab.getPosition()){ switch (tab.getPosition()){
case 0: case 0:
DisplayStatusFragment displayStatusFragment = ((DisplayStatusFragment) fragment);
if( displayStatusFragment != null )
displayStatusFragment.scrollToTop();
Helper.cacheStatusClear(getApplicationContext(), null);
updateHomeCounter();
break;
case 2: case 2:
case 3: case 3:
DisplayStatusFragment displayStatusFragment = ((DisplayStatusFragment) fragment); displayStatusFragment = ((DisplayStatusFragment) fragment);
if( displayStatusFragment != null ) if( displayStatusFragment != null )
displayStatusFragment.scrollToTop(); displayStatusFragment.scrollToTop();
break; break;
@ -291,6 +362,8 @@ public class MainActivity extends AppCompatActivity
DisplayNotificationsFragment displayNotificationsFragment = ((DisplayNotificationsFragment) fragment); DisplayNotificationsFragment displayNotificationsFragment = ((DisplayNotificationsFragment) fragment);
if( displayNotificationsFragment != null ) if( displayNotificationsFragment != null )
displayNotificationsFragment.scrollToTop(); displayNotificationsFragment.scrollToTop();
Helper.cacheNotificationsClear(getApplicationContext(), null);
updateNotifCounter();
break; break;
} }
} }
@ -354,7 +427,11 @@ public class MainActivity extends AppCompatActivity
Intent intent = new Intent(MainActivity.this, SearchResultActivity.class); Intent intent = new Intent(MainActivity.this, SearchResultActivity.class);
intent.putExtra("search", query); intent.putExtra("search", query);
startActivity(intent); startActivity(intent);
return true; toolbar_search.setQuery("", false);
toolbar_search.setIconified(true);
toolbarTitle.setVisibility(View.VISIBLE);
pp_actionBar.setVisibility(View.VISIBLE);
return false;
} }
@Override @Override
public boolean onQueryTextChange(String newText) { public boolean onQueryTextChange(String newText) {
@ -421,15 +498,14 @@ public class MainActivity extends AppCompatActivity
.diskCache(new UnlimitedDiskCache(cacheDir)) .diskCache(new UnlimitedDiskCache(cacheDir))
.build(); .build();
imageLoader.init(configImg); imageLoader.init(configImg);
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
options = new DisplayImageOptions.Builder().displayer(new RoundedBitmapDisplayer(90)).cacheInMemory(false) options = new DisplayImageOptions.Builder().displayer(new RoundedBitmapDisplayer(90)).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build(); .cacheOnDisk(true).resetViewBeforeLoading(true).build();
headerLayout = navigationView.getHeaderView(0); headerLayout = navigationView.getHeaderView(0);
String prefKeyOauthTokenT = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
Account account = new AccountDAO(getApplicationContext(), db).getAccountByToken(prefKeyOauthTokenT); Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(userId);
updateHeaderAccountInfo(MainActivity.this, account, headerLayout, imageLoader, options); updateHeaderAccountInfo(MainActivity.this, account, headerLayout, imageLoader, options);
loadPPInActionBar(MainActivity.this, account.getAvatar()); loadPPInActionBar(MainActivity.this, account.getAvatar());
//Locked account can see follow request //Locked account can see follow request
@ -545,6 +621,21 @@ public class MainActivity extends AppCompatActivity
String sharedSubject = intent.getStringExtra(Intent.EXTRA_SUBJECT); String sharedSubject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null) { if (sharedText != null) {
/* Some apps don't send the URL as the first part of the EXTRA_TEXT,
the BBC News app being one such, in this case find where the URL
is and strip that out into sharedText.
*/
Matcher matcher;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT)
matcher = Patterns.WEB_URL.matcher(sharedText);
else
matcher = Helper.urlPattern.matcher(sharedText);
while (matcher.find()){
int matchStart = matcher.start(1);
int matchEnd = matcher.end();
sharedText = sharedText.substring(matchStart, matchEnd);
}
new RetrieveMetaDataAsyncTask(sharedText, MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Intent intentToot = new Intent(getApplicationContext(), TootActivity.class); Intent intentToot = new Intent(getApplicationContext(), TootActivity.class);
Bundle b = new Bundle(); Bundle b = new Bundle();
b.putString("sharedSubject", sharedSubject); b.putString("sharedSubject", sharedSubject);
@ -599,6 +690,7 @@ public class MainActivity extends AppCompatActivity
//Hide search bar on back pressed //Hide search bar on back pressed
if( !toolbar_search.isIconified()){ if( !toolbar_search.isIconified()){
toolbar_search.setIconified(true); toolbar_search.setIconified(true);
return;
} }
if( viewPager.getVisibility() == View.VISIBLE){ if( viewPager.getVisibility() == View.VISIBLE){
if (stackBack.size() > 1) { if (stackBack.size() > 1) {
@ -615,7 +707,7 @@ public class MainActivity extends AppCompatActivity
unCheckAllMenuItems(navigationView); unCheckAllMenuItems(navigationView);
toot.setVisibility(View.VISIBLE); toot.setVisibility(View.VISIBLE);
//Manages theme for icon colors //Manages theme for icon colors
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_DARK){ if( theme == Helper.THEME_DARK){
changeDrawableColor(getApplicationContext(), R.drawable.ic_reply,R.color.dark_text); changeDrawableColor(getApplicationContext(), R.drawable.ic_reply,R.color.dark_text);
@ -800,22 +892,25 @@ public class MainActivity extends AppCompatActivity
@Override @Override
public void onResume(){ public void onResume(){
super.onResume(); super.onResume();
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); MainActivity.activityResumed();
boolean bubbles = sharedpreferences.getBoolean(Helper.SET_BUBBLE_COUNTER, true); updateNotifCounter();
if( bubbles){ updateHomeCounter();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {refreshData();}
}, 1000);
}
//Proceeds to update of the authenticated account //Proceeds to update of the authenticated account
if(Helper.isLoggedIn(getApplicationContext())) if(Helper.isLoggedIn(getApplicationContext()))
new UpdateAccountInfoByIDAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new UpdateAccountInfoByIDAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@Override
protected void onPause() {
super.onPause();
MainActivity.activityPaused();
}
@Override
public void onDestroy(){
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data);
}
@SuppressWarnings("StatementWithEmptyBody") @SuppressWarnings("StatementWithEmptyBody")
@Override @Override
@ -838,20 +933,25 @@ public class MainActivity extends AppCompatActivity
} }
toolbarTitle.setText(item.getTitle()); toolbarTitle.setText(item.getTitle());
if (id == R.id.nav_home) { if (id == R.id.nav_home) {
//noinspection ConstantConditions if( tabLayout.getSelectedTabPosition() != 0)
tabLayout.getTabAt(0).select(); //noinspection ConstantConditions
tabLayout.getTabAt(0).select();
return true; return true;
} else if( id == R.id.nav_notification){ } else if( id == R.id.nav_notification){
//noinspection ConstantConditions if( tabLayout.getSelectedTabPosition() != 1)
tabLayout.getTabAt(1).select(); //noinspection ConstantConditions
tabLayout.getTabAt(1).select();
return true; return true;
}else if (id == R.id.nav_local) { }else if (id == R.id.nav_local) {
//noinspection ConstantConditions
tabLayout.getTabAt(2).select(); if( tabLayout.getSelectedTabPosition() != 2)
//noinspection ConstantConditions
tabLayout.getTabAt(2).select();
return true; return true;
} else if (id == R.id.nav_global) { } else if (id == R.id.nav_global) {
//noinspection ConstantConditions if( tabLayout.getSelectedTabPosition() != 3)
tabLayout.getTabAt(3).select(); //noinspection ConstantConditions
tabLayout.getTabAt(3).select();
return true; return true;
} }
DisplayStatusFragment statusFragment; DisplayStatusFragment statusFragment;
@ -948,7 +1048,16 @@ public class MainActivity extends AppCompatActivity
} }
@Override
public void onRetrieveMetaData(boolean error, String image, String title, String description) {
if( !error) {
Intent intentSendImage = new Intent(Helper.RECEIVE_PICTURE);
intentSendImage.putExtra("image", image);
intentSendImage.putExtra("title", title);
intentSendImage.putExtra("description", description);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentSendImage);
}
}
/** /**
@ -973,26 +1082,29 @@ public class MainActivity extends AppCompatActivity
//Selection comes from another menu, no action to do //Selection comes from another menu, no action to do
DisplayStatusFragment statusFragment; DisplayStatusFragment statusFragment;
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
switch (position) { if (position == 0) {
case 0: homeFragment = new DisplayStatusFragment();
homeFragment = new DisplayStatusFragment(); bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.HOME);
bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.HOME); homeFragment.setArguments(bundle);
homeFragment.setArguments(bundle); return homeFragment;
return homeFragment; }else if( position == 1) {
case 1: notificationsFragment = new DisplayNotificationsFragment();
notificationsFragment = new DisplayNotificationsFragment(); return notificationsFragment;
return notificationsFragment; }else if( position == 2 && display_local) {
case 2:
statusFragment = new DisplayStatusFragment(); statusFragment = new DisplayStatusFragment();
bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.LOCAL); bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.LOCAL);
statusFragment.setArguments(bundle); statusFragment.setArguments(bundle);
return statusFragment; return statusFragment;
case 3: }else if( position == 2 && !display_local){
statusFragment = new DisplayStatusFragment(); statusFragment = new DisplayStatusFragment();
bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.PUBLIC); bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.PUBLIC);
statusFragment.setArguments(bundle); statusFragment.setArguments(bundle);
return statusFragment; return statusFragment;
}else if (position == 3){
statusFragment = new DisplayStatusFragment();
bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.PUBLIC);
statusFragment.setArguments(bundle);
return statusFragment;
} }
return null; return null;
} }
@ -1003,40 +1115,8 @@ public class MainActivity extends AppCompatActivity
} }
} }
private void refreshData(){
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
String prefKeyOauthTokenT = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); public void updateHomeCounter(){
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account account = new AccountDAO(getApplicationContext(), db).getAccountByToken(prefKeyOauthTokenT);
if( account != null){
String last_refresh = sharedpreferences.getString(Helper.LAST_BUBBLE_REFRESH_NOTIF + account.getId(), null);
Date last_refresh_date = Helper.stringToDate(getApplicationContext(), last_refresh);
if (last_refresh_date == null || (new Date().getTime() - last_refresh_date.getTime()) >= TimeUnit.SECONDS.toMillis(60)) {
if( notificationsFragment != null ){
notificationsFragment.update();
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ account.getId(),Helper.dateToString(getApplicationContext(), new Date()));
editor.apply();
}
}
last_refresh = sharedpreferences.getString(Helper.LAST_BUBBLE_REFRESH_HOME + account.getId(), null);
last_refresh_date = Helper.stringToDate(getApplicationContext(), last_refresh);
if (last_refresh_date == null || (new Date().getTime() - last_refresh_date.getTime()) >= TimeUnit.SECONDS.toMillis(60)) {
if( homeFragment != null ){
homeFragment.update();
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_BUBBLE_REFRESH_HOME+ account.getId(),Helper.dateToString(getApplicationContext(), new Date()));
editor.apply();
}
}
}
}
public void updateHomeCounter(int newHomeCount){
if( tabLayout.getTabAt(0) == null ) if( tabLayout.getTabAt(0) == null )
return; return;
//noinspection ConstantConditions //noinspection ConstantConditions
@ -1044,20 +1124,17 @@ public class MainActivity extends AppCompatActivity
if( tabHome == null) if( tabHome == null)
return; return;
TextView tabCounterHome = (TextView) tabHome.findViewById(R.id.tab_counter); TextView tabCounterHome = (TextView) tabHome.findViewById(R.id.tab_counter);
tabCounterHome.setText(String.valueOf(newHomeCount)); tabCounterHome.setText(String.valueOf(Helper.getUnreadToots(getApplicationContext(), null)));
if( newHomeCount > 0){ if( Helper.getUnreadToots(getApplicationContext(), null) > 0){
//New data are available //New data are available
//The fragment is not displayed, so the counter is displayed //The fragment is not displayed, so the counter is displayed
if( tabLayout.getSelectedTabPosition() != 0) tabCounterHome.setVisibility(View.VISIBLE);
tabCounterHome.setVisibility(View.VISIBLE);
else
tabCounterHome.setVisibility(View.GONE);
}else { }else {
tabCounterHome.setVisibility(View.GONE); tabCounterHome.setVisibility(View.GONE);
} }
} }
public void updateNotifCounter(int newNotifCount){ public void updateNotifCounter(){
if(tabLayout.getTabAt(1) == null) if(tabLayout.getTabAt(1) == null)
return; return;
//noinspection ConstantConditions //noinspection ConstantConditions
@ -1065,15 +1142,25 @@ public class MainActivity extends AppCompatActivity
if( tabNotif == null) if( tabNotif == null)
return; return;
TextView tabCounterNotif = (TextView) tabNotif.findViewById(R.id.tab_counter); TextView tabCounterNotif = (TextView) tabNotif.findViewById(R.id.tab_counter);
tabCounterNotif.setText(String.valueOf(newNotifCount)); tabCounterNotif.setText(String.valueOf(Helper.getUnreadNotifications(getApplicationContext(), null)));
if( newNotifCount > 0){ if( Helper.getUnreadNotifications(getApplicationContext(), null) > 0){
if( tabLayout.getSelectedTabPosition() != 1) tabCounterNotif.setVisibility(View.VISIBLE);
tabCounterNotif.setVisibility(View.VISIBLE);
else
tabCounterNotif.setVisibility(View.GONE);
}else { }else {
tabCounterNotif.setVisibility(View.GONE); tabCounterNotif.setVisibility(View.GONE);
} }
} }
public static boolean isActivityVisible() {
return activityVisible;
}
private static void activityResumed() {
activityVisible = true;
}
private static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
} }

View File

@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application <application
android:name="fr.gouv.etalab.mastodon.activities.MainApplication" android:name="fr.gouv.etalab.mastodon.activities.MainApplication"
@ -34,10 +35,18 @@
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppThemeDark"> android:theme="@style/AppThemeDark">
<service
android:name="fr.gouv.etalab.mastodon.services.StreamingService"
android:exported="false"/>
<receiver android:name="fr.gouv.etalab.mastodon.services.BootService" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity <activity
android:name="fr.gouv.etalab.mastodon.activities.MainActivity" android:name="fr.gouv.etalab.mastodon.activities.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop" android:launchMode="singleTask"
android:windowSoftInputMode = "adjustResize" android:windowSoftInputMode = "adjustResize"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppThemeDark_NoActionBar"> android:theme="@style/AppThemeDark_NoActionBar">
@ -70,7 +79,6 @@
<activity android:name="fr.gouv.etalab.mastodon.activities.HashTagActivity" <activity android:name="fr.gouv.etalab.mastodon.activities.HashTagActivity"
android:windowSoftInputMode="stateAlwaysHidden" android:windowSoftInputMode="stateAlwaysHidden"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:noHistory="true"
android:label="@string/app_name" android:label="@string/app_name"
/> />
<activity android:name="fr.gouv.etalab.mastodon.activities.WebviewConnectActivity" <activity android:name="fr.gouv.etalab.mastodon.activities.WebviewConnectActivity"
@ -82,7 +90,6 @@
android:label="@string/app_name" android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTask" android:launchMode="singleTask"
android:noHistory="true"
/> />
<activity android:name="fr.gouv.etalab.mastodon.activities.MediaActivity" <activity android:name="fr.gouv.etalab.mastodon.activities.MediaActivity"
android:label="@string/app_name" android:label="@string/app_name"
@ -127,6 +134,11 @@
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme_NoActionBar" android:theme="@style/AppTheme_NoActionBar"
/> />
<activity android:name="fr.gouv.etalab.mastodon.activities.EditProfileActivity"
android:windowSoftInputMode="stateAlwaysHidden"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
/>
<activity <activity
android:name="fr.gouv.etalab.mastodon.activities.SplashActivity" android:name="fr.gouv.etalab.mastodon.activities.SplashActivity"
android:windowSoftInputMode="stateAlwaysHidden" android:windowSoftInputMode="stateAlwaysHidden"

View File

@ -2424,4 +2424,261 @@ digit_one, 0x0031
digit_zero, 0x0030 digit_zero, 0x0030
family_man_woman_boy, 0x1f468,0x1f469,0x1f466 family_man_woman_boy, 0x1f468,0x1f469,0x1f466
couple_with_heart_woman_man, 0x1f469,0x2764,0x1f468 couple_with_heart_woman_man, 0x1f469,0x2764,0x1f468
kiss_woman_man, 0x1f469,0x2764,0x1f48b,0x1f468 kiss_woman_man, 0x1f469,0x2764,0x1f48b,0x1f468
ad, 0x1f1e6,0x1f1e9
ao, 0x1f1e6,0x1f1f4
af, 0x1f1e6,0x1f1eb
ai, 0x1f1e6,0x1f1ee
aq, 0x1f1e6,0x1f1f6
ag, 0x1f1e6,0x1f1ec
al, 0x1f1e6,0x1f1f1
ar, 0x1f1e6,0x1f1f7
as, 0x1f1e6,0x1f1f8
am, 0x1f1e6,0x1f1f2
aw, 0x1f1e6,0x1f1fc
au, 0x1f1e6,0x1f1fa
at, 0x1f1e6,0x1f1f9
ax, 0x1f1e6,0x1f1fd
az, 0x1f1e6,0x1f1ff
bs, 0x1f1e7,0x1f1f8
bh, 0x1f1e7,0x1f1ed
bd, 0x1f1e7,0x1f1e9
bb, 0x1f1e7,0x1f1e7
by, 0x1f1e7,0x1f1fe
be, 0x1f1e7,0x1f1ea
bz, 0x1f1e7,0x1f1ff
bj, 0x1f1e7,0x1f1ef
bm, 0x1f1e7,0x1f1f2
bt, 0x1f1e7,0x1f1f9
bo, 0x1f1e7,0x1f1f4
ba, 0x1f1e7,0x1f1e6
bw, 0x1f1e7,0x1f1fc
br, 0x1f1e7,0x1f1f7
io, 0x1f1ee,0x1f1f4
vg, 0x1f1fb,0x1f1ec
bn, 0x1f1e7,0x1f1f3
bg, 0x1f1e7,0x1f1ec
bf, 0x1f1e7,0x1f1eb
bi, 0x1f1e7,0x1f1ee
kh, 0x1f1f0,0x1f1ed
cm, 0x1f1e8,0x1f1f2
ca, 0x1f1e8,0x1f1e6
ic, 0x1f1ee,0x1f1e8
cv, 0x1f1e8,0x1f1fb
bq, 0x1f1e7,0x1f1f6
ky, 0x1f1f0,0x1f1fe
cf, 0x1f1e8,0x1f1eb
td, 0x1f1f9,0x1f1e9
cl, 0x1f1e8,0x1f1f1
cn, 0x1f1e8,0x1f1f3
cx, 0x1f1e8,0x1f1fd
cc, 0x1f1e8,0x1f1e8
co, 0x1f1e8,0x1f1f4
km, 0x1f1f0,0x1f1f2
cg, 0x1f1e8,0x1f1ec
cd, 0x1f1e8,0x1f1e9
ck, 0x1f1e8,0x1f1f0
cr, 0x1f1e8,0x1f1f7
ci, 0x1f1e8,0x1f1ee
hr, 0x1f1ed,0x1f1f7
cu, 0x1f1e8,0x1f1fa
cw, 0x1f1e8,0x1f1fc
cy, 0x1f1e8,0x1f1fe
cz, 0x1f1e8,0x1f1ff
dk, 0x1f1e9,0x1f1f0
dj, 0x1f1e9,0x1f1ef
dm, 0x1f1e9,0x1f1f2
do, 0x1f1e9,0x1f1f4
ec, 0x1f1ea,0x1f1e8
eg, 0x1f1ea,0x1f1ec
sv, 0x1f1f8,0x1f1fb
gq, 0x1f1ec,0x1f1f6
er, 0x1f1ea,0x1f1f7
ee, 0x1f1ea,0x1f1ea
et, 0x1f1ea,0x1f1f9
eu, 0x1f1ea,0x1f1fa
fk, 0x1f1eb,0x1f1f0
fo, 0x1f1eb,0x1f1f4
fj, 0x1f1eb,0x1f1ef
fi, 0x1f1eb,0x1f1ee
fr, 0x1f1eb,0x1f1f7
gf, 0x1f1ec,0x1f1eb
pf, 0x1f1f5,0x1f1eb
tf, 0x1f1f9,0x1f1eb
ga, 0x1f1ec,0x1f1e6
gb, 0x1f1ec,0x1f1e7
gm, 0x1f1ec,0x1f1f2
ge, 0x1f1ec,0x1f1ea
de, 0x1f1e9,0x1f1ea
gh, 0x1f1ec,0x1f1ed
gi, 0x1f1ec,0x1f1ee
gr, 0x1f1ec,0x1f1f7
gl, 0x1f1ec,0x1f1f1
gd, 0x1f1ec,0x1f1e9
gp, 0x1f1ec,0x1f1f5
gu, 0x1f1ec,0x1f1fa
gt, 0x1f1ec,0x1f1f9
gg, 0x1f1ec,0x1f1ec
gn, 0x1f1ec,0x1f1f3
gw, 0x1f1ec,0x1f1fc
gy, 0x1f1ec,0x1f1fe
ht, 0x1f1ed,0x1f1f9
hn, 0x1f1ed,0x1f1f3
hk, 0x1f1ed,0x1f1f0
hu, 0x1f1ed,0x1f1fa
is, 0x1f1ee,0x1f1f8
in, 0x1f1ee,0x1f1f3
id, 0x1f1ee,0x1f1e9
ir, 0x1f1ee,0x1f1f7
iq, 0x1f1ee,0x1f1f6
ie, 0x1f1ee,0x1f1ea
im, 0x1f1ee,0x1f1f2
il, 0x1f1ee,0x1f1f1
it, 0x1f1ee,0x1f1f9
jm, 0x1f1ef,0x1f1f2
jp, 0x1f1ef,0x1f1f5
je, 0x1f1ef,0x1f1ea
jo, 0x1f1ef,0x1f1f4
kz, 0x1f1f0,0x1f1ff
ke, 0x1f1f0,0x1f1ea
ki, 0x1f1f0,0x1f1ee
xk, 0x1f1fd,0x1f1f0
kw, 0x1f1f0,0x1f1fc
kg, 0x1f1f0,0x1f1ec
la, 0x1f1f1,0x1f1e6
lv, 0x1f1f1,0x1f1fb
lb, 0x1f1f1,0x1f1e7
ls, 0x1f1f1,0x1f1f8
lr, 0x1f1f1,0x1f1f7
ly, 0x1f1f1,0x1f1fe
li, 0x1f1f1,0x1f1ee
lt, 0x1f1f1,0x1f1f9
lu, 0x1f1f1,0x1f1fa
mo, 0x1f1f2,0x1f1f4
mk, 0x1f1f2,0x1f1f0
mg, 0x1f1f2,0x1f1ec
mw, 0x1f1f2,0x1f1fc
my, 0x1f1f2,0x1f1fe
mv, 0x1f1f2,0x1f1fb
ml, 0x1f1f2,0x1f1f1
mt, 0x1f1f2,0x1f1f9
mh, 0x1f1f2,0x1f1ed
mq, 0x1f1f2,0x1f1f6
mr, 0x1f1f2,0x1f1f7
mu, 0x1f1f2,0x1f1fa
yt, 0x1f1fe,0x1f1f9
mx, 0x1f1f2,0x1f1fd
fm, 0x1f1eb,0x1f1f2
md, 0x1f1f2,0x1f1e9
mc, 0x1f1f2,0x1f1e8
mn, 0x1f1f2,0x1f1f3
me, 0x1f1f2,0x1f1ea
ms, 0x1f1f2,0x1f1f8
ma, 0x1f1f2,0x1f1e6
mz, 0x1f1f2,0x1f1ff
mm, 0x1f1f2,0x1f1f2
na, 0x1f1f3,0x1f1e6
nr, 0x1f1f3,0x1f1f7
np, 0x1f1f3,0x1f1f5
nl, 0x1f1f3,0x1f1f1
nc, 0x1f1f3,0x1f1e8
nz, 0x1f1f3,0x1f1ff
ni, 0x1f1f3,0x1f1ee
ne, 0x1f1f3,0x1f1ea
ng, 0x1f1f3,0x1f1ec
nu, 0x1f1f3,0x1f1fa
nf, 0x1f1f3,0x1f1eb
kp, 0x1f1f0,0x1f1f5
mp, 0x1f1f2,0x1f1f5
no, 0x1f1f3,0x1f1f4
om, 0x1f1f4,0x1f1f2
pk, 0x1f1f5,0x1f1f0
pw, 0x1f1f5,0x1f1fc
ps, 0x1f1f5,0x1f1f8
pa, 0x1f1f5,0x1f1e6
pg, 0x1f1f5,0x1f1ec
py, 0x1f1f5,0x1f1fe
pe, 0x1f1f5,0x1f1ea
ph, 0x1f1f5,0x1f1ed
pn, 0x1f1f5,0x1f1f3
pl, 0x1f1f5,0x1f1f1
pt, 0x1f1f5,0x1f1f9
pr, 0x1f1f5,0x1f1f7
qa, 0x1f1f6,0x1f1e6
re, 0x1f1f7,0x1f1ea
ro, 0x1f1f7,0x1f1f4
ru, 0x1f1f7,0x1f1fa
rw, 0x1f1f7,0x1f1fc
ws, 0x1f1fc,0x1f1f8
sm, 0x1f1f8,0x1f1f2
st, 0x1f1f8,0x1f1f9
sa, 0x1f1f8,0x1f1e6
sn, 0x1f1f8,0x1f1f3
rs, 0x1f1f7,0x1f1f8
sc, 0x1f1f8,0x1f1e8
sl, 0x1f1f8,0x1f1f1
sg, 0x1f1f8,0x1f1ec
sx, 0x1f1f8,0x1f1fd
sk, 0x1f1f8,0x1f1f0
si, 0x1f1f8,0x1f1ee
gs, 0x1f1ec,0x1f1f8
sb, 0x1f1f8,0x1f1e7
so, 0x1f1f8,0x1f1f4
za, 0x1f1ff,0x1f1e6
kr, 0x1f1f0,0x1f1f7
ss, 0x1f1f8,0x1f1f8
es, 0x1f1ea,0x1f1f8
lk, 0x1f1f1,0x1f1f0
bl, 0x1f1e7,0x1f1f1
sh, 0x1f1f8,0x1f1ed
kn, 0x1f1f0,0x1f1f3
lc, 0x1f1f1,0x1f1e8
pm, 0x1f1f5,0x1f1f2
vc, 0x1f1fb,0x1f1e8
sd, 0x1f1f8,0x1f1e9
sr, 0x1f1f8,0x1f1f7
sz, 0x1f1f8,0x1f1ff
se, 0x1f1f8,0x1f1ea
ch, 0x1f1e8,0x1f1ed
sy, 0x1f1f8,0x1f1fe
tw, 0x1f1f9,0x1f1fc
tj, 0x1f1f9,0x1f1ef
tz, 0x1f1f9,0x1f1ff
th, 0x1f1f9,0x1f1ed
tl, 0x1f1f9,0x1f1f1
tg, 0x1f1f9,0x1f1ec
tk, 0x1f1f9,0x1f1f0
to, 0x1f1f9,0x1f1f4
tt, 0x1f1f9,0x1f1f9
tn, 0x1f1f9,0x1f1f3
tr, 0x1f1f9,0x1f1f7
tm, 0x1f1f9,0x1f1f2
tc, 0x1f1f9,0x1f1e8
tv, 0x1f1f9,0x1f1fb
vi, 0x1f1fb,0x1f1ee
ug, 0x1f1fa,0x1f1ec
ua, 0x1f1fa,0x1f1e6
ae, 0x1f1e6,0x1f1ea
us, 0x1f1fa,0x1f1f8
uy, 0x1f1fa,0x1f1fe
uz, 0x1f1fa,0x1f1ff
vu, 0x1f1fb,0x1f1fa
va, 0x1f1fb,0x1f1e6
ve, 0x1f1fb,0x1f1ea
vn, 0x1f1fb,0x1f1f3
wf, 0x1f1fc,0x1f1eb
eh, 0x1f1ea,0x1f1ed
ye, 0x1f1fe,0x1f1ea
zm, 0x1f1ff,0x1f1f2
zw, 0x1f1ff,0x1f1fc
ac, 0x1f1e6,0x1f1e8
ta, 0x1f1f9,0x1f1e6
bv, 0x1f1e7,0x1f1fb
hm, 0x1f1ed,0x1f1f2
sj, 0x1f1f8,0x1f1ef
um, 0x1f1fa,0x1f1f2
ea, 0x1f1ea,0x1f1e6
cp, 0x1f1e8,0x1f1f5
dg, 0x1f1e9,0x1f1ec
dz, 0x1f1e9,0x1f1ff
mf, 0x1f1f2,0x1f1eb
Can't render this file because it has a wrong number of fields in line 168.

View File

@ -23,23 +23,27 @@ import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.SpannableString; import android.util.Log;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveDeveloperAccountsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveDeveloperAccountsAsyncTask;
import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.asynctasks.RetrieveRelationshipAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveRemoteAccountsAsyncTask;
import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.client.Entities.Relationship;
import fr.gouv.etalab.mastodon.drawers.AccountSearchDevAdapter;
import fr.gouv.etalab.mastodon.helper.ExpandableHeightListView;
import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearcAccountshInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRelationshipInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRemoteAccountInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearchDevelopersAccountshInterface;
import mastodon.etalab.gouv.fr.mastodon.R; import mastodon.etalab.gouv.fr.mastodon.R;
@ -48,9 +52,12 @@ import mastodon.etalab.gouv.fr.mastodon.R;
* About activity * About activity
*/ */
public class AboutActivity extends AppCompatActivity implements OnRetrieveSearcAccountshInterface { public class AboutActivity extends AppCompatActivity implements OnRetrieveRemoteAccountInterface, OnRetrieveSearchDevelopersAccountshInterface, OnRetrieveRelationshipInterface {
private Button about_developer; private List<Account> developers = new ArrayList<>();
private List<Account> contributors = new ArrayList<>();
private AccountSearchDevAdapter accountSearchWebAdapterDeveloper;
private AccountSearchDevAdapter accountSearchWebAdapterContributors;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Override @Override
@ -73,7 +80,8 @@ public class AboutActivity extends AppCompatActivity implements OnRetrieveSearcA
about_version.setText(getResources().getString(R.string.about_vesrion, version)); about_version.setText(getResources().getString(R.string.about_vesrion, version));
} catch (PackageManager.NameNotFoundException ignored) {} } catch (PackageManager.NameNotFoundException ignored) {}
about_developer = (Button) findViewById(R.id.about_developer); ExpandableHeightListView lv_developers = (ExpandableHeightListView) findViewById(R.id.lv_developers);
ExpandableHeightListView lv_contributors = (ExpandableHeightListView) findViewById(R.id.lv_contributors);
Button about_code = (Button) findViewById(R.id.about_code); Button about_code = (Button) findViewById(R.id.about_code);
Button about_license = (Button) findViewById(R.id.about_license); Button about_license = (Button) findViewById(R.id.about_license);
Button about_thekinrar = (Button) findViewById(R.id.about_thekinrar); Button about_thekinrar = (Button) findViewById(R.id.about_thekinrar);
@ -93,17 +101,7 @@ public class AboutActivity extends AppCompatActivity implements OnRetrieveSearcA
startActivity(browserIntent); startActivity(browserIntent);
} }
}); });
if(Helper.isLoggedIn(getApplicationContext())) {
about_developer.setEnabled(false);
new RetrieveDeveloperAccountsAsyncTask(getApplicationContext(),AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
about_developer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://mastodon.etalab.gouv.fr/@tschneider"));
startActivity(browserIntent);
}
});
about_license.setOnClickListener(new View.OnClickListener() { about_license.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -120,32 +118,21 @@ public class AboutActivity extends AppCompatActivity implements OnRetrieveSearcA
} }
}); });
TextView about_thanks = (TextView) findViewById(R.id.about_thanks_dev);
String currentText = about_thanks.getText().toString();
SpannableString spanned_thanks = new SpannableString(currentText);
int startPosition = spanned_thanks.toString().indexOf("@PhotonQyv");
int endPosition = startPosition + "@PhotonQyv".length();
spanned_thanks.setSpan(new ClickableSpan() {
@Override
public void onClick(View textView) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://mastodon.xyz/@PhotonQyv"));
startActivity(browserIntent);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
}
}, startPosition, endPosition, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
about_thanks.setText(spanned_thanks, TextView.BufferType.SPANNABLE);
about_thanks.setMovementMethod(LinkMovementMethod.getInstance());
if( theme == Helper.THEME_LIGHT) { if( theme == Helper.THEME_LIGHT) {
about_developer.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
about_code.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white)); about_code.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
about_thekinrar.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white)); about_thekinrar.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
about_translation.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white)); about_translation.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
about_license.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white)); about_license.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
} }
lv_contributors.setExpanded(true);
lv_developers.setExpanded(true);
accountSearchWebAdapterContributors = new AccountSearchDevAdapter(AboutActivity.this, contributors);
lv_contributors.setAdapter(accountSearchWebAdapterContributors);
accountSearchWebAdapterDeveloper = new AccountSearchDevAdapter(AboutActivity.this, developers);
lv_developers.setAdapter(accountSearchWebAdapterDeveloper);
new RetrieveDeveloperAccountsAsyncTask(getApplicationContext(), AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@ -160,22 +147,116 @@ public class AboutActivity extends AppCompatActivity implements OnRetrieveSearcA
} }
} }
@Override @Override
public void onRetrieveSearchAccounts(APIResponse apiResponse) { public void onRetrieveRemoteAccount(boolean error, String name, String username, String instance_name, boolean locked, String avatar, String bio, String statusCount, String followingCount, String followersCount) {
about_developer.setEnabled(true); if( error){
final List<Account> accounts = apiResponse.getAccounts(); return;
if( accounts != null && accounts.size() > 0 && accounts.get(0) != null) { }
about_developer.setOnClickListener(null); Account account = new Account();
about_developer.setOnClickListener(new View.OnClickListener() { account.setInstance(instance_name);
@Override account.setAcct(username + "@" + instance_name);
public void onClick(View v) { account.setAvatar(avatar);
Intent intent = new Intent(AboutActivity.this, ShowAccountActivity.class); account.setDisplay_name(username);
Bundle b = new Bundle(); account.setStatuses_count_str(statusCount);
b.putString("accountId", accounts.get(0).getId()); account.setFollowers_count_str(followersCount);
intent.putExtras(b); account.setFollowing_count_str(followingCount);
startActivity(intent); account.setUsername(name);
} account.setLocked(locked);
}); account.setNote(bio);
account.setFollowing(false);
account.setRemote(true);
if( username.equals("@tschneider")) {
developers.add(account);
accountSearchWebAdapterDeveloper.notifyDataSetChanged();
}else {
contributors.add(account);
accountSearchWebAdapterContributors.notifyDataSetChanged();
}
}
@Override
public void onRetrieveSearchDevelopersAccounts(ArrayList<Account> accounts) {
if( accounts == null || accounts.size() == 0) {
new RetrieveRemoteAccountsAsyncTask("tschneider", "mastodon.etalab.gouv.fr", AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveRemoteAccountsAsyncTask("PhotonQyv", "mastodon.xyz", AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveRemoteAccountsAsyncTask("angrytux", "social.tchncs.de", AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
return;
}
boolean tschneider = false;
boolean PhotonQyv = false;
boolean angrytux = false;
for(Account account: accounts){
if( account.getUsername().equals("tschneider")){
account.setFollowing(false);
account.setRemote(false);
developers.add(account);
accountSearchWebAdapterDeveloper.notifyDataSetChanged();
tschneider = true;
new RetrieveRelationshipAsyncTask(getApplicationContext(), account.getId(),AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
if( account.getUsername().equals("PhotonQyv")){
account.setFollowing(false);
account.setRemote(false);
contributors.add(account);
accountSearchWebAdapterContributors.notifyDataSetChanged();
PhotonQyv = true;
new RetrieveRelationshipAsyncTask(getApplicationContext(), account.getId(),AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
if( account.getUsername().equals("angrytux")){
account.setFollowing(false);
account.setRemote(false);
contributors.add(account);
accountSearchWebAdapterContributors.notifyDataSetChanged();
angrytux = true;
new RetrieveRelationshipAsyncTask(getApplicationContext(), account.getId(),AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
if( !tschneider)
new RetrieveRemoteAccountsAsyncTask("tschneider", "mastodon.etalab.gouv.fr", AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if( !PhotonQyv)
new RetrieveRemoteAccountsAsyncTask("PhotonQyv", "mastodon.xyz", AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if( !angrytux)
new RetrieveRemoteAccountsAsyncTask("angrytux", "social.tchncs.de", AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
public void onResume(){
super.onResume();
if( developers != null && developers.size() > 0){
for(Account account: developers){
new RetrieveRelationshipAsyncTask(getApplicationContext(), account.getId(),AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
if( contributors != null && contributors.size() > 0){
for(Account account: contributors){
new RetrieveRelationshipAsyncTask(getApplicationContext(), account.getId(),AboutActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
@Override
public void onRetrieveRelationship(Relationship relationship, Error error) {
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, "");
if( error != null){
return;
}
for( int i = 0 ; i < developers.size() ; i++){
if( contributors.get(i).getId() != null && developers.get(i).getId().equals(relationship.getId())){
developers.get(i).setFollowing(relationship.isFollowing() || userId.trim().equals(relationship.getId()));
accountSearchWebAdapterDeveloper.notifyDataSetChanged();
break;
}
}
for( int i = 0 ; i < contributors.size() ; i++){
if( contributors.get(i).getId() != null && contributors.get(i).getId().equals(relationship.getId())){
contributors.get(i).setFollowing(relationship.isFollowing() || userId.trim().equals(relationship.getId()));
accountSearchWebAdapterContributors.notifyDataSetChanged();
break;
}
} }
} }
} }

View File

@ -1,4 +1,3 @@
package fr.gouv.etalab.mastodon.fragments;
/* Copyright 2017 Thomas Schneider /* Copyright 2017 Thomas Schneider
* *
* This file is a part of Mastalab * This file is a part of Mastalab
@ -13,25 +12,32 @@ package fr.gouv.etalab.mastodon.fragments;
* *
* You should have received a copy of the GNU General Public License along with Mastalab; if not, * You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.activities;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.SharedPreferences;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable; import android.text.Editable;
import android.text.Html; import android.text.Html;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Base64; import android.util.Base64;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
@ -40,35 +46,43 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import fr.gouv.etalab.mastodon.activities.MainActivity;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountInfoAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountInfoAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.UpdateCredentialAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.UpdateCredentialAsyncTask;
import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Error; import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAccountInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAccountInterface;
import fr.gouv.etalab.mastodon.interfaces.OnUpdateCredentialInterface; import fr.gouv.etalab.mastodon.interfaces.OnUpdateCredentialInterface;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import mastodon.etalab.gouv.fr.mastodon.R; import mastodon.etalab.gouv.fr.mastodon.R;
/** /**
* Created by Thomas on 04/06/2017. * Created by Thomas on 27/08/2017.
* Fragment for profile settings * Edit profile activity
*/ */
public class SettingsProfileFragment extends Fragment implements OnRetrieveAccountInterface, OnUpdateCredentialInterface {
public class EditProfileActivity extends AppCompatActivity implements OnRetrieveAccountInterface, OnUpdateCredentialInterface {
private Context context;
private EditText set_profile_name, set_profile_description; private EditText set_profile_name, set_profile_description;
private ImageView set_profile_picture, set_header_picture; private ImageView set_profile_picture, set_header_picture;
private Button set_change_profile_picture, set_change_header_picture, set_profile_save; private Button set_change_profile_picture, set_change_header_picture, set_profile_save;
@ -79,59 +93,128 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
private static final int PICK_IMAGE_PROFILE = 6545; private static final int PICK_IMAGE_PROFILE = 6545;
private String profile_picture, header_picture, profile_username, profile_note; private String profile_picture, header_picture, profile_username, profile_note;
private Bitmap profile_picture_bmp, profile_header_bmp; private Bitmap profile_picture_bmp, profile_header_bmp;
private TextView title;
private ImageView pp_actionBar;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_settings_profile, container, false); SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_LIGHT){
setTheme(R.style.AppTheme);
}else {
setTheme(R.style.AppThemeDark);
}
setContentView(R.layout.activity_edit_profile);
set_profile_name = (EditText) rootView.findViewById(R.id.set_profile_name); ActionBar actionBar = getSupportActionBar();
set_profile_description = (EditText) rootView.findViewById(R.id.set_profile_description); if( actionBar != null) {
set_profile_picture = (ImageView) rootView.findViewById(R.id.set_profile_picture); LayoutInflater inflater = (LayoutInflater) this.getSystemService(android.content.Context.LAYOUT_INFLATER_SERVICE);
set_header_picture = (ImageView) rootView.findViewById(R.id.set_header_picture); View view = inflater.inflate(R.layout.conversation_action_bar, null);
set_change_profile_picture = (Button) rootView.findViewById(R.id.set_change_profile_picture); actionBar.setCustomView(view, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
set_change_header_picture = (Button) rootView.findViewById(R.id.set_change_header_picture); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
set_profile_save = (Button) rootView.findViewById(R.id.set_profile_save); title = (TextView) actionBar.getCustomView().findViewById(R.id.toolbar_title);
set_header_picture_overlay = (TextView) rootView.findViewById(R.id.set_header_picture_overlay); pp_actionBar = (ImageView) actionBar.getCustomView().findViewById(R.id.pp_actionBar);
title.setText(R.string.settings_title_profile);
ImageView close_conversation = (ImageView) actionBar.getCustomView().findViewById(R.id.close_conversation);
if( close_conversation != null){
close_conversation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}else{
setTitle(R.string.settings_title_profile);
}
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
Account account = new AccountDAO(getApplicationContext(),db).getAccountByID(userId);
String url = account.getAvatar();
if( url.startsWith("/") ){
url = "https://" + Helper.getLiveInstance(getApplicationContext()) + account.getAvatar();
}
ImageLoader imageLoader = ImageLoader.getInstance();
File cacheDir = new File(getCacheDir(), getString(R.string.app_name));
ImageLoaderConfiguration configImg = new ImageLoaderConfiguration.Builder(this)
.imageDownloader(new PatchBaseImageDownloader(getApplicationContext()))
.threadPoolSize(5)
.threadPriority(Thread.MIN_PRIORITY + 3)
.denyCacheImageMultipleSizesInMemory()
.diskCache(new UnlimitedDiskCache(cacheDir))
.build();
this.imageLoader = ImageLoader.getInstance();
this.options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
imageLoader.init(configImg);
DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
imageLoader.loadImage(url, options, new SimpleImageLoadingListener(){
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
BitmapDrawable ppDrawable = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(loadedImage, (int) Helper.convertDpToPixel(25, getApplicationContext()), (int) Helper.convertDpToPixel(25, getApplicationContext()), true));
if( pp_actionBar != null){
pp_actionBar.setImageDrawable(ppDrawable);
} else if( getSupportActionBar() != null){
getSupportActionBar().setIcon(ppDrawable);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
@Override
public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
}});
set_profile_name = (EditText) findViewById(R.id.set_profile_name);
set_profile_description = (EditText) findViewById(R.id.set_profile_description);
set_profile_picture = (ImageView) findViewById(R.id.set_profile_picture);
set_header_picture = (ImageView) findViewById(R.id.set_header_picture);
set_change_profile_picture = (Button) findViewById(R.id.set_change_profile_picture);
set_change_header_picture = (Button) findViewById(R.id.set_change_header_picture);
set_profile_save = (Button) findViewById(R.id.set_profile_save);
set_header_picture_overlay = (TextView) findViewById(R.id.set_header_picture_overlay);
set_profile_save.setEnabled(false); set_profile_save.setEnabled(false);
set_change_header_picture.setEnabled(false); set_change_header_picture.setEnabled(false);
set_change_profile_picture.setEnabled(false); set_change_profile_picture.setEnabled(false);
set_profile_name.setEnabled(false); set_profile_name.setEnabled(false);
set_profile_description.setEnabled(false); set_profile_description.setEnabled(false);
context = getContext();
imageLoader = ImageLoader.getInstance(); new RetrieveAccountInfoAsyncTask(getApplicationContext(), EditProfileActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
new RetrieveAccountInfoAsyncTask(context, SettingsProfileFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_LIGHT) { if( theme == Helper.THEME_LIGHT) {
set_profile_save.setTextColor(ContextCompat.getColor(context, R.color.white)); set_profile_save.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
} }
return rootView;
} }
@Override @Override
public void onCreate(Bundle saveInstance) { public boolean onOptionsItemSelected(MenuItem item) {
super.onCreate(saveInstance); switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
} }
@Override @Override
public void onAttach(Context context) { public boolean onCreateOptionsMenu(Menu menu) {
super.onAttach(context); // Inflate the menu; this adds items to the action bar if it is present.
this.context = context; getMenuInflater().inflate(R.menu.main_media, menu);
return true;
} }
@Override @Override
public void onRetrieveAccount(Account account, Error error) { public void onRetrieveAccount(Account account, Error error) {
if( error != null ){ if( error != null ){
Toast.makeText(context,R.string.toast_error, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toast_error, Toast.LENGTH_LONG).show();
return; return;
} }
set_profile_name.setText(account.getDisplay_name()); set_profile_name.setText(account.getDisplay_name());
@ -161,7 +244,7 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
String content = s.toString().substring(0,160); String content = s.toString().substring(0,160);
set_profile_description.setText(content); set_profile_description.setText(content);
set_profile_description.setSelection(set_profile_description.getText().length()); set_profile_description.setSelection(set_profile_description.getText().length());
Toast.makeText(context,R.string.note_no_space,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.note_no_space,Toast.LENGTH_LONG).show();
} }
} }
}); });
@ -177,7 +260,7 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
String content = s.toString().substring(0,30); String content = s.toString().substring(0,30);
set_profile_name.setText(content); set_profile_name.setText(content);
set_profile_name.setSelection(set_profile_name.getText().length()); set_profile_name.setSelection(set_profile_name.getText().length());
Toast.makeText(context,R.string.username_no_space,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.username_no_space,Toast.LENGTH_LONG).show();
} }
} }
}); });
@ -233,9 +316,9 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
else else
profile_note = null; profile_note = null;
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(EditProfileActivity.this);
LayoutInflater inflater = ((MainActivity) context).getLayoutInflater(); LayoutInflater inflater = EditProfileActivity.this.getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_profile, null); @SuppressLint("InflateParams") View dialogView = inflater.inflate(R.layout.dialog_profile, null);
dialogBuilder.setView(dialogView); dialogBuilder.setView(dialogView);
ImageView back_ground_image = (ImageView) dialogView.findViewById(R.id.back_ground_image); ImageView back_ground_image = (ImageView) dialogView.findViewById(R.id.back_ground_image);
@ -248,7 +331,7 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
if( profile_note != null) if( profile_note != null)
dialog_profile_description.setText(profile_note); dialog_profile_description.setText(profile_note);
if( profile_header_bmp != null) { if( profile_header_bmp != null) {
BitmapDrawable background = new BitmapDrawable(context.getResources(), profile_header_bmp); BitmapDrawable background = new BitmapDrawable(getApplicationContext().getResources(), profile_header_bmp);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
//noinspection deprecation //noinspection deprecation
back_ground_image.setBackgroundDrawable(background); back_ground_image.setBackgroundDrawable(background);
@ -264,7 +347,7 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
} }
} }
if( profile_picture_bmp != null) { if( profile_picture_bmp != null) {
BitmapDrawable background = new BitmapDrawable(context.getResources(), profile_picture_bmp); BitmapDrawable background = new BitmapDrawable(getApplicationContext().getResources(), profile_picture_bmp);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
//noinspection deprecation //noinspection deprecation
dialog_profile_picture.setBackgroundDrawable(background); dialog_profile_picture.setBackgroundDrawable(background);
@ -283,7 +366,7 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
set_profile_save.setEnabled(false); set_profile_save.setEnabled(false);
new UpdateCredentialAsyncTask(context, profile_username, profile_note, profile_picture, header_picture, SettingsProfileFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new UpdateCredentialAsyncTask(getApplicationContext(), profile_username, profile_note, profile_picture, header_picture, EditProfileActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
}); });
dialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { dialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@ -305,16 +388,16 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_HEADER && resultCode == Activity.RESULT_OK) { if (requestCode == PICK_IMAGE_HEADER && resultCode == Activity.RESULT_OK) {
if (data == null) { if (data == null) {
Toast.makeText(context,R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();
return; return;
} }
try { try {
InputStream inputStream = context.getContentResolver().openInputStream(data.getData()); InputStream inputStream = getApplicationContext().getContentResolver().openInputStream(data.getData());
BufferedInputStream bufferedInputStream; BufferedInputStream bufferedInputStream;
if (inputStream != null) { if (inputStream != null) {
bufferedInputStream = new BufferedInputStream(inputStream); bufferedInputStream = new BufferedInputStream(inputStream);
}else { }else {
Toast.makeText(context,R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();
return; return;
} }
Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream); Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream);
@ -326,21 +409,21 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
header_picture = "data:image/png;base64, " + Base64.encodeToString(byteArray, Base64.DEFAULT); header_picture = "data:image/png;base64, " + Base64.encodeToString(byteArray, Base64.DEFAULT);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Toast.makeText(context,R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();
e.printStackTrace(); e.printStackTrace();
} }
}else if(requestCode == PICK_IMAGE_PROFILE && resultCode == Activity.RESULT_OK) { }else if(requestCode == PICK_IMAGE_PROFILE && resultCode == Activity.RESULT_OK) {
if (data == null) { if (data == null) {
Toast.makeText(context,R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();
return; return;
} }
try { try {
InputStream inputStream = context.getContentResolver().openInputStream(data.getData()); InputStream inputStream = getApplicationContext().getContentResolver().openInputStream(data.getData());
BufferedInputStream bufferedInputStream; BufferedInputStream bufferedInputStream;
if (inputStream != null) { if (inputStream != null) {
bufferedInputStream = new BufferedInputStream(inputStream); bufferedInputStream = new BufferedInputStream(inputStream);
}else { }else {
Toast.makeText(context,R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();
return; return;
} }
Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream); Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream);
@ -351,7 +434,7 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
byte[] byteArray = byteArrayOutputStream .toByteArray(); byte[] byteArray = byteArrayOutputStream .toByteArray();
profile_picture = "data:image/png;base64, " + Base64.encodeToString(byteArray, Base64.DEFAULT); profile_picture = "data:image/png;base64, " + Base64.encodeToString(byteArray, Base64.DEFAULT);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Toast.makeText(context,R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -360,10 +443,11 @@ public class SettingsProfileFragment extends Fragment implements OnRetrieveAccou
@Override @Override
public void onUpdateCredential(APIResponse apiResponse) { public void onUpdateCredential(APIResponse apiResponse) {
if( apiResponse.getError() != null){ if( apiResponse.getError() != null){
Toast.makeText(context, R.string.toast_error, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.toast_error, Toast.LENGTH_LONG).show();
return; return;
} }
Toast.makeText(context, R.string.toast_update_credential_ok, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.toast_update_credential_ok, Toast.LENGTH_LONG).show();
set_profile_save.setEnabled(true); set_profile_save.setEnabled(true);
} }
} }

View File

@ -362,6 +362,8 @@ public class MediaActivity extends AppCompatActivity {
@Override @Override
public void onPrepared(MediaPlayer mp) { public void onPrepared(MediaPlayer mp) {
loader.setVisibility(View.GONE); loader.setVisibility(View.GONE);
mp.start();
mp.setLooping(true);
} }
}); });
videoView.setVisibility(View.VISIBLE); videoView.setVisibility(View.VISIBLE);

View File

@ -261,7 +261,7 @@ public class RemoteFollowActivity extends AppCompatActivity implements OnRetriev
@Override @Override
public void onRetrieveRemoteAccount(boolean error, String name, String username, boolean locked, String avatar, String bio, int statusCount, int followingCount, int followersCount) { public void onRetrieveRemoteAccount(boolean error, String name, String username, String instance_name, boolean locked, String avatar, String bio, String statusCount, String followingCount, String followersCount) {
loader.setVisibility(View.GONE); loader.setVisibility(View.GONE);
rf_search.setEnabled(true); rf_search.setEnabled(true);
if( error){ if( error){
@ -274,9 +274,9 @@ public class RemoteFollowActivity extends AppCompatActivity implements OnRetriev
account.setAcct(screen_name + "@" + instance_name); account.setAcct(screen_name + "@" + instance_name);
account.setAvatar(avatar); account.setAvatar(avatar);
account.setDisplay_name(username); account.setDisplay_name(username);
account.setStatuses_count(statusCount); account.setStatuses_count_str(statusCount);
account.setFollowers_count(followersCount); account.setFollowers_count_str(followersCount);
account.setFollowing_count(followingCount); account.setFollowing_count_str(followingCount);
account.setUsername(name); account.setUsername(name);
account.setLocked(locked); account.setLocked(locked);
account.setNote(bio); account.setNote(bio);

View File

@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
@ -89,6 +90,8 @@ import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAccountInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAccountInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsAccountInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsAccountInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRelationshipInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRelationshipInterface;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import mastodon.etalab.gouv.fr.mastodon.R; import mastodon.etalab.gouv.fr.mastodon.R;
import fr.gouv.etalab.mastodon.client.Entities.Relationship; import fr.gouv.etalab.mastodon.client.Entities.Relationship;
@ -122,6 +125,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
private BroadcastReceiver hide_header; private BroadcastReceiver hide_header;
private boolean isHiddingShowing = false; private boolean isHiddingShowing = false;
private LinearLayout main_header_container; private LinearLayout main_header_container;
private ImageView header_edit_profile;
public enum action{ public enum action{
FOLLOW, FOLLOW,
@ -149,6 +153,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
account_follow = (FloatingActionButton) findViewById(R.id.account_follow); account_follow = (FloatingActionButton) findViewById(R.id.account_follow);
account_follow_request = (TextView) findViewById(R.id.account_follow_request); account_follow_request = (TextView) findViewById(R.id.account_follow_request);
main_header_container = (LinearLayout) findViewById(R.id.main_header_container); main_header_container = (LinearLayout) findViewById(R.id.main_header_container);
header_edit_profile = (ImageView) findViewById(R.id.header_edit_profile);
account_follow.setEnabled(false); account_follow.setEnabled(false);
if(b != null){ if(b != null){
accountId = b.getString("accountId"); accountId = b.getString("accountId");
@ -298,6 +303,14 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
LocalBroadcastManager.getInstance(this).registerReceiver(hide_header, new IntentFilter(Helper.HEADER_ACCOUNT + String.valueOf(instanceValue))); LocalBroadcastManager.getInstance(this).registerReceiver(hide_header, new IntentFilter(Helper.HEADER_ACCOUNT + String.valueOf(instanceValue)));
} }
header_edit_profile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ShowAccountActivity.this, EditProfileActivity.class);
startActivity(intent);
}
});
} }
@ -520,6 +533,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
account_follow.setEnabled(true); account_follow.setEnabled(true);
if( accountId != null && accountId.equals(userId)){ if( accountId != null && accountId.equals(userId)){
account_follow.setVisibility(View.GONE); account_follow.setVisibility(View.GONE);
header_edit_profile.setVisibility(View.VISIBLE);
}else if( relationship.isBlocking()){ }else if( relationship.isBlocking()){
account_follow.setImageResource(R.drawable.ic_unlock_alt); account_follow.setImageResource(R.drawable.ic_unlock_alt);
doAction = action.UNBLOCK; doAction = action.UNBLOCK;

View File

@ -17,11 +17,14 @@ package fr.gouv.etalab.mastodon.activities;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.net.Uri; import android.net.Uri;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
@ -49,6 +52,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.webkit.URLUtil;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView; import android.widget.AutoCompleteTextView;
@ -66,6 +70,8 @@ import android.widget.TextView;
import android.widget.TimePicker; import android.widget.TimePicker;
import android.widget.Toast; import android.widget.Toast;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.BinaryHttpResponseHandler;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
@ -74,9 +80,13 @@ import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -86,6 +96,7 @@ import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import cz.msebera.android.httpclient.Header;
import fr.gouv.etalab.mastodon.asynctasks.PostStatusAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.PostStatusAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveSearchAccountsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveSearchAccountsAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.UploadActionAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.UploadActionAsyncTask;
@ -136,7 +147,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
private EditText toot_cw_content; private EditText toot_cw_content;
private LinearLayout toot_reply_content_container; private LinearLayout toot_reply_content_container;
private Status tootReply = null; private Status tootReply = null;
private String sharedContent, sharedSubject; private String sharedContent, sharedSubject, sharedContentIni;
private CheckBox toot_sensitive; private CheckBox toot_sensitive;
public long currentToId; public long currentToId;
private long restored; private long restored;
@ -148,7 +159,9 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
private HorizontalScrollView picture_scrollview; private HorizontalScrollView picture_scrollview;
private int currentCursorPosition, searchLength; private int currentCursorPosition, searchLength;
private TextView toot_space_left; private TextView toot_space_left;
private String initialContent;
private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 754; private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 754;
private BroadcastReceiver receive_picture;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -240,6 +253,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
if(b != null) { if(b != null) {
tootReply = b.getParcelable("tootReply"); tootReply = b.getParcelable("tootReply");
sharedContent = b.getString("sharedContent", null); sharedContent = b.getString("sharedContent", null);
sharedContentIni = b.getString("sharedContent", null);
sharedSubject = b.getString("sharedSubject", null); sharedSubject = b.getString("sharedSubject", null);
// ACTION_SEND route // ACTION_SEND route
if (b.getInt("uriNumber", 0) == 1) { if (b.getInt("uriNumber", 0) == 1) {
@ -261,6 +275,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
} }
restored = b.getLong("restored", -1); restored = b.getLong("restored", -1);
} }
initialContent = toot_content.getText().toString();
if( restored != -1 ){ if( restored != -1 ){
toot_it.setVisibility(View.GONE); toot_it.setVisibility(View.GONE);
invalidateOptionsMenu(); invalidateOptionsMenu();
@ -299,21 +314,75 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
}}); }});
if( sharedContent != null ){ //Shared content if( sharedContent != null ){ //Shared content
if( sharedSubject != null){ if( sharedSubject != null){
sharedContent = sharedSubject + "\n\n" + sharedContent; sharedContent = sharedSubject + "\n\n" + sharedContent;
} }
receive_picture = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String image = intent.getStringExtra("image");
String title = intent.getStringExtra("title");
String description = intent.getStringExtra("description");
if( description != null && description.length() > 20 ){
if( description.length() > 200 )
description = description.substring(0,199) + "";
if( title != null)
sharedContent = title + "\n\n" + description + "\n\n" + sharedContentIni;
else
sharedContent = description + "\n\n" + sharedContentIni;
toot_content.setText(sharedContent);
toot_space_left.setText(String.valueOf(toot_content.length()));
toot_content.setSelection(toot_content.getText().length());
}
if( image != null){
AsyncHttpClient client = new AsyncHttpClient();
String[] allowedTypes = new String[] { "image/png","image/jpeg" };
client.get(image, new BinaryHttpResponseHandler(allowedTypes) {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {
OutputStream f;
try {
f = new FileOutputStream(getCacheDir() + URLUtil.guessFileName(image, null, null));
picture_scrollview.setVisibility(View.VISIBLE);
InputStream bis = new ByteArrayInputStream(binaryData);
loading_picture.setVisibility(View.VISIBLE);
toot_picture.setEnabled(false);
new UploadActionAsyncTask(getApplicationContext(),bis,TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
f.write(binaryData);
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {
error.printStackTrace();
}
});
}
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(receive_picture, new IntentFilter(Helper.RECEIVE_PICTURE));
toot_content.setText( String.format("\n%s", sharedContent)); toot_content.setText( String.format("\n%s", sharedContent));
toot_space_left.setText(String.valueOf(toot_content.length()));
} }
attachments = new ArrayList<>(); attachments = new ArrayList<>();
int charsInCw = 0; int charsInCw = 0;
int charsInToot = 0; int charsInToot = 0;
uploadSharedImage(sharedUri); if (!sharedUri.isEmpty()) {
uploadSharedImage(sharedUri);
}
boolean isAccountPrivate = account.isLocked(); boolean isAccountPrivate = account.isLocked();
if(isAccountPrivate){ if(isAccountPrivate){
if( tootReply == null) { if( tootReply == null) {
visibility = "private"; visibility = "private";
toot_visibility.setImageResource(R.drawable.ic_action_lock_closed);
}else { }else {
if( visibility.equals("direct") ){ if( visibility.equals("direct") ){
toot_visibility.setImageResource(R.drawable.ic_local_post_office); toot_visibility.setImageResource(R.drawable.ic_local_post_office);
@ -523,6 +592,14 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
} }
} }
@Override
public void onDestroy(){
super.onDestroy();
if( receive_picture != null)
LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_picture);
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, public void onRequestPermissionsResult(int requestCode,
@NonNull String permissions[], @NonNull int[] grantResults) { @NonNull String permissions[], @NonNull int[] grantResults) {
@ -546,6 +623,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
mToast.show(); mToast.show();
} }
// Handles uploading shared images // Handles uploading shared images
public void uploadSharedImage(ArrayList<Uri> uri) public void uploadSharedImage(ArrayList<Uri> uri)
{ {
@ -769,6 +847,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
//Clear content //Clear content
toot_content.setText(""); toot_content.setText("");
toot_cw_content.setText(""); toot_cw_content.setText("");
toot_space_left.setText(0);
if( attachments != null) { if( attachments != null) {
for (Attachment attachment : attachments) { for (Attachment attachment : attachments) {
View namebar = findViewById(Integer.parseInt(attachment.getId())); View namebar = findViewById(Integer.parseInt(attachment.getId()));
@ -842,6 +921,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
//Adds the shorter text_url of attachment at the end of the toot //Adds the shorter text_url of attachment at the end of the toot
int selectionBefore = toot_content.getSelectionStart(); int selectionBefore = toot_content.getSelectionStart();
toot_content.setText(toot_content.getText().toString() + "\n" + attachment.getText_url()); toot_content.setText(toot_content.getText().toString() + "\n" + attachment.getText_url());
toot_space_left.setText(String.valueOf(toot_content.length()));
//Moves the cursor //Moves the cursor
if (selectionBefore >= 0) if (selectionBefore >= 0)
toot_content.setSelection(selectionBefore); toot_content.setSelection(selectionBefore);
@ -890,6 +970,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
//Clears the text_url at the end of the toot for this attachment //Clears the text_url at the end of the toot for this attachment
int selectionBefore = toot_content.getSelectionStart(); int selectionBefore = toot_content.getSelectionStart();
toot_content.setText(toot_content.getText().toString().replace(attachment.getText_url(), "")); toot_content.setText(toot_content.getText().toString().replace(attachment.getText_url(), ""));
toot_space_left.setText(String.valueOf(toot_content.length()));
//Moves the cursor //Moves the cursor
if (selectionBefore >= 0) if (selectionBefore >= 0)
toot_content.setSelection(selectionBefore); toot_content.setSelection(selectionBefore);
@ -977,6 +1058,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
//Clear the toot //Clear the toot
toot_content.setText(""); toot_content.setText("");
toot_cw_content.setText(""); toot_cw_content.setText("");
toot_space_left.setText("0");
if( attachments != null) { if( attachments != null) {
for (Attachment attachment : attachments) { for (Attachment attachment : attachments) {
View namebar = findViewById(Integer.parseInt(attachment.getId())); View namebar = findViewById(Integer.parseInt(attachment.getId()));
@ -1059,6 +1141,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
if( currentCursorPosition < oldContent.length() - 1) if( currentCursorPosition < oldContent.length() - 1)
newContent += oldContent.substring(currentCursorPosition, oldContent.length()-1); newContent += oldContent.substring(currentCursorPosition, oldContent.length()-1);
toot_content.setText(newContent); toot_content.setText(newContent);
toot_space_left.setText(String.valueOf(toot_content.length()));
toot_content.setSelection(newPosition); toot_content.setSelection(newPosition);
AccountsSearchAdapter accountsListAdapter = new AccountsSearchAdapter(TootActivity.this, new ArrayList<Account>()); AccountsSearchAdapter accountsListAdapter = new AccountsSearchAdapter(TootActivity.this, new ArrayList<Account>());
toot_content.setThreshold(1); toot_content.setThreshold(1);
@ -1132,6 +1215,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
} }
String content = status.getContent(); String content = status.getContent();
toot_content.setText(content); toot_content.setText(content);
toot_space_left.setText(String.valueOf(toot_content.length()));
toot_content.setSelection(toot_content.getText().length()); toot_content.setSelection(toot_content.getText().length());
switch (status.getVisibility()){ switch (status.getVisibility()){
case "public": case "public":
@ -1163,6 +1247,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
else else
setTitle(R.string.toot_title); setTitle(R.string.toot_title);
} }
initialContent = toot_content.getText().toString();
toot_space_left.setText(String.valueOf(toot_content.getText().length() + toot_cw_content.getText().length())); toot_space_left.setText(String.valueOf(toot_content.getText().length() + toot_cw_content.getText().length()));
} }
@ -1245,9 +1330,10 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
//Put a "<space>dot<space>" at the end of all mentioned account to force capitalization //Put a "<space>dot<space>" at the end of all mentioned account to force capitalization
toot_content.append(" . "); toot_content.append(" . ");
} }
toot_space_left.setText(String.valueOf(toot_content.length()));
toot_content.setSelection(toot_content.getText().length()); //Put cursor at the end toot_content.setSelection(toot_content.getText().length()); //Put cursor at the end
} }
initialContent = toot_content.getText().toString();
} }
@ -1256,7 +1342,8 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
//Nothing to store here.... //Nothing to store here....
if(toot_content.getText().toString().trim().length() == 0 && (attachments == null || attachments.size() <1) && toot_cw_content.getText().toString().trim().length() == 0) if(toot_content.getText().toString().trim().length() == 0 && (attachments == null || attachments.size() <1) && toot_cw_content.getText().toString().trim().length() == 0)
return; return;
if( initialContent.equals(toot_content.getText().toString()))
return;
Status toot = new Status(); Status toot = new Status();
toot.setSensitive(isSensitive); toot.setSensitive(isSensitive);
toot.setMedia_attachments(attachments); toot.setMedia_attachments(attachments);
@ -1311,6 +1398,4 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
changeDrawableColor(TootActivity.this, R.drawable.ic_check, R.color.white); changeDrawableColor(TootActivity.this, R.drawable.ic_check, R.color.white);
} }
} }
} }

View File

@ -147,6 +147,20 @@ public class WebviewActivity extends AppCompatActivity {
this.url = newUrl; this.url = newUrl;
} }
@Override
public void onPause(){
super.onPause();
if( webView != null)
webView.onPause();
}
@Override
public void onResume(){
super.onResume();
if( webView != null)
webView.onResume();
}
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (webView.canGoBack()){ if (webView.canGoBack()){
@ -159,6 +173,7 @@ public class WebviewActivity extends AppCompatActivity {
@Override @Override
public void onDestroy(){ public void onDestroy(){
super.onDestroy(); super.onDestroy();
if( webView != null)
webView.destroy();
} }
} }

View File

@ -16,9 +16,13 @@ package fr.gouv.etalab.mastodon.asynctasks;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import java.util.ArrayList;
import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearcAccountshInterface; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearchDevelopersAccountshInterface;
/** /**
@ -29,23 +33,32 @@ import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearcAccountshInterface;
public class RetrieveDeveloperAccountsAsyncTask extends AsyncTask<Void, Void, Void> { public class RetrieveDeveloperAccountsAsyncTask extends AsyncTask<Void, Void, Void> {
private Context context; private Context context;
private APIResponse apiResponse; private OnRetrieveSearchDevelopersAccountshInterface listener;
private OnRetrieveSearcAccountshInterface listener; private ArrayList<Account> accounts;
public RetrieveDeveloperAccountsAsyncTask(Context context, OnRetrieveSearcAccountshInterface onRetrieveSearcAccountshInterface){ public RetrieveDeveloperAccountsAsyncTask(Context context, OnRetrieveSearchDevelopersAccountshInterface onRetrieveSearchDevelopersAccountshInterface){
this.context = context; this.context = context;
this.listener = onRetrieveSearcAccountshInterface; this.listener = onRetrieveSearchDevelopersAccountshInterface;
} }
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
API api = new API(context); API api = new API(context);
apiResponse = api.searchDeveloper(); accounts = new ArrayList<>();
APIResponse apiResponse = api.searchAccounts("@tschneider@mastodon.etalab.gouv.fr", 1);
if( apiResponse.getAccounts() != null && apiResponse.getAccounts().size() > 0)
accounts.add(apiResponse.getAccounts().get(0));
apiResponse = api.searchAccounts("@PhotonQyv@mastodon.xyz",1);
if( apiResponse.getAccounts() != null && apiResponse.getAccounts().size() > 0)
accounts.add(apiResponse.getAccounts().get(0));
apiResponse = api.searchAccounts("@angrytux@social.tchncs.de",1);
if( apiResponse.getAccounts() != null && apiResponse.getAccounts().size() > 0)
accounts.add(apiResponse.getAccounts().get(0));
return null; return null;
} }
@Override @Override
protected void onPostExecute(Void result) { protected void onPostExecute(Void result) {
listener.onRetrieveSearchAccounts(apiResponse); listener.onRetrieveSearchDevelopersAccounts(accounts);
} }
} }

View File

@ -15,10 +15,8 @@
package fr.gouv.etalab.mastodon.asynctasks; package fr.gouv.etalab.mastodon.asynctasks;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log;
import java.util.Date;
import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.APIResponse;
@ -61,8 +59,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
this.max_id = max_id; this.max_id = max_id;
this.listener = onRetrieveFeedsInterface; this.listener = onRetrieveFeedsInterface;
this.refreshData = true; this.refreshData = true;
updateTimeRefresh();
} }
public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
@ -73,7 +69,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
this.targetedID = targetedID; this.targetedID = targetedID;
this.showMediaOnly = showMediaOnly; this.showMediaOnly = showMediaOnly;
this.refreshData = true; this.refreshData = true;
updateTimeRefresh();
} }
public RetrieveFeedsAsyncTask(Context context, Type action, String tag, String targetedID, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ public RetrieveFeedsAsyncTask(Context context, Type action, String tag, String targetedID, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
this.context = context; this.context = context;
@ -83,21 +78,11 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
this.targetedID = targetedID; this.targetedID = targetedID;
this.tag = tag; this.tag = tag;
this.refreshData = true; this.refreshData = true;
updateTimeRefresh();
} }
public RetrieveFeedsAsyncTask(Context context, Type action, String max_id, boolean refreshData, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
this.context = context;
this.action = action;
this.max_id = max_id;
this.listener = onRetrieveFeedsInterface;
this.refreshData = refreshData;
updateTimeRefresh();
}
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
API api = new API(context); API api = new API(context);
switch (action){ switch (action){
case HOME: case HOME:
@ -134,14 +119,4 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
protected void onPostExecute(Void result) { protected void onPostExecute(Void result) {
listener.onRetrieveFeeds(apiResponse, refreshData); listener.onRetrieveFeeds(apiResponse, refreshData);
} }
private void updateTimeRefresh(){
if( action == Type.HOME) {
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_BUBBLE_REFRESH_HOME + userId, Helper.dateToString(context, new Date()));
editor.apply();
}
}
} }

View File

@ -0,0 +1,75 @@
/* 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.asynctasks;
import android.os.AsyncTask;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.IOException;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMetaDataInterface;
/**
* Created by Thomas on 02/09/2017.
* Retrieves metadata of a remote page
*/
public class RetrieveMetaDataAsyncTask extends AsyncTask<Void, Void, Void> {
private OnRetrieveMetaDataInterface listener;
private String url;
private boolean error = false;
private String image, title, description;
public RetrieveMetaDataAsyncTask(String url, OnRetrieveMetaDataInterface onRetrieveRemoteAccountInterface){
this.url = url;
this.listener = onRetrieveRemoteAccountInterface;
}
@Override
protected Void doInBackground(Void... params) {
String userAgent = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36";
try {
Document document = Jsoup.connect(url).userAgent(userAgent).get();
Elements metaOgTitle = document.select("meta[property=og:title]");
if (metaOgTitle != null) {
title = metaOgTitle.attr("content");
} else {
title = document.title();
}
Elements metaOgDescription = document.select("meta[property=og:description]");
if (metaOgDescription != null) {
description = metaOgDescription.attr("content");
} else {
description = "";
}
Elements metaOgImage = document.select("meta[property=og:image]");
if (metaOgImage != null) {
image = metaOgImage.attr("content");
}
} catch (IOException | IndexOutOfBoundsException e) {
error = true;
}
return null;
}
@Override
protected void onPostExecute(Void result) {
listener.onRetrieveMetaData(error, image, title, description);
}
}

View File

@ -15,14 +15,9 @@
package fr.gouv.etalab.mastodon.asynctasks; package fr.gouv.etalab.mastodon.asynctasks;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask; import android.os.AsyncTask;
import java.util.Date;
import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveNotificationsInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveNotificationsInterface;
@ -51,20 +46,8 @@ public class RetrieveNotificationsAsyncTask extends AsyncTask<Void, Void, Void>
this.userId = userId; this.userId = userId;
this.token = token; this.token = token;
this.refreshData = true; this.refreshData = true;
updateTimeRefresh();
} }
public RetrieveNotificationsAsyncTask(Context context, String instance, String token, String max_id, String acct, String userId, boolean refreshData, OnRetrieveNotificationsInterface onRetrieveNotificationsInterface){
this.context = context;
this.max_id = max_id;
this.listener = onRetrieveNotificationsInterface;
this.acct = acct;
this.instance = instance;
this.userId = userId;
this.token = token;
this.refreshData = refreshData;
updateTimeRefresh();
}
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
@ -82,10 +65,4 @@ public class RetrieveNotificationsAsyncTask extends AsyncTask<Void, Void, Void>
listener.onRetrieveNotifications(apiResponse, acct, userId, refreshData); listener.onRetrieveNotifications(apiResponse, acct, userId, refreshData);
} }
private void updateTimeRefresh(){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ userId,Helper.dateToString(context, new Date()));
editor.apply();
}
} }

View File

@ -16,9 +16,11 @@ package fr.gouv.etalab.mastodon.asynctasks;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log;
import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.Entities.Relationship; import fr.gouv.etalab.mastodon.client.Entities.Relationship;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRelationshipInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRelationshipInterface;
/** /**
@ -42,7 +44,6 @@ public class RetrieveRelationshipAsyncTask extends AsyncTask<Void, Void, Void> {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
api = new API(context); api = new API(context);
relationship = api.getRelationship(accountId); relationship = api.getRelationship(accountId);
return null; return null;

View File

@ -15,10 +15,11 @@
package fr.gouv.etalab.mastodon.asynctasks; package fr.gouv.etalab.mastodon.asynctasks;
import android.os.AsyncTask; import android.os.AsyncTask;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
import java.io.IOException;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRemoteAccountInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRemoteAccountInterface;
@ -32,7 +33,7 @@ public class RetrieveRemoteAccountsAsyncTask extends AsyncTask<Void, Void, Void>
private OnRetrieveRemoteAccountInterface listener; private OnRetrieveRemoteAccountInterface listener;
private String url; private String url;
private String avatar, name, username, bio; private String avatar, name, username, bio;
private int statusCount, followingCount, followersCount; private String statusCount, followingCount, followersCount;
private boolean islocked; private boolean islocked;
private boolean error = false; private boolean error = false;
private String instance; private String instance;
@ -56,23 +57,24 @@ public class RetrieveRemoteAccountsAsyncTask extends AsyncTask<Void, Void, Void>
Elements nameElement = document.getElementsByClass("name"); Elements nameElement = document.getElementsByClass("name");
name = nameElement.get(0).getElementsByClass("p-name").get(0).html(); name = nameElement.get(0).getElementsByClass("p-name").get(0).html();
username = nameElement.get(0).getElementsByTag("span").get(1).html(); username = nameElement.get(0).getElementsByTag("span").get(1).html();
islocked = nameElement.get(0).getElementsByClass("fa-lock") != null; islocked = (nameElement.get(0).getElementsByClass("fa-lock") != null && nameElement.get(0).getElementsByClass("fa-lock").size() > 0);
Elements bioElement = document.getElementsByClass("bio"); Elements bioElement = document.getElementsByClass("bio");
bio = bioElement.get(0).html(); bio = bioElement.get(0).html();
Elements countElement = document.getElementsByClass("counter-number"); Elements countElement = document.getElementsByClass("counter-number");
statusCount = Integer.parseInt(countElement.get(0).html()); statusCount = countElement.get(0).html();
followingCount = Integer.parseInt(countElement.get(1).html()); followingCount = countElement.get(1).html();
followersCount = Integer.parseInt(countElement.get(2).html()); followersCount = countElement.get(2).html();
} catch (IOException | IndexOutOfBoundsException e) { } catch (Exception e) {
error = true; error = true;
e.printStackTrace();
} }
return null; return null;
} }
@Override @Override
protected void onPostExecute(Void result) { protected void onPostExecute(Void result) {
listener.onRetrieveRemoteAccount(error, name, username, islocked, avatar, bio, statusCount, followingCount, followersCount); listener.onRetrieveRemoteAccount(error, name, username, instance, islocked, avatar, bio, statusCount, followingCount, followersCount);
} }
} }

View File

@ -18,6 +18,7 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Log;
import com.evernote.android.job.JobManager; import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest; import com.evernote.android.job.JobRequest;
@ -68,6 +69,7 @@ public class RetrieveScheduledTootsAsyncTask extends AsyncTask<Void, Void, Void>
}else{ }else{
jobIds = new int[]{}; jobIds = new int[]{};
} }
if( storedStatuses != null && storedStatuses.size() > 0 ){ if( storedStatuses != null && storedStatuses.size() > 0 ){
for(StoredStatus ss: storedStatuses){ for(StoredStatus ss: storedStatuses){
if (!Helper.isJobPresent(jobIds, ss.getJobId())){ if (!Helper.isJobPresent(jobIds, ss.getJobId())){

View File

@ -188,12 +188,12 @@ public class API {
get("/accounts/verify_credentials", null, new JsonHttpResponseHandler() { get("/accounts/verify_credentials", null, new JsonHttpResponseHandler() {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
account = parseAccountResponse(response); account = parseAccountResponse(context, response);
} }
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response) { public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
try { try {
account = parseAccountResponse(response.getJSONObject(0)); account = parseAccountResponse(context, response.getJSONObject(0));
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -217,12 +217,12 @@ public class API {
get(String.format("/accounts/%s",accountId), null, new JsonHttpResponseHandler() { get(String.format("/accounts/%s",accountId), null, new JsonHttpResponseHandler() {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
account = parseAccountResponse(response); account = parseAccountResponse(context, response);
} }
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response) { public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
try { try {
account = parseAccountResponse(response.getJSONObject(0)); account = parseAccountResponse(context, response.getJSONObject(0));
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -330,7 +330,7 @@ public class API {
get(String.format("/accounts/%s/statuses", accountId), params, new JsonHttpResponseHandler() { get(String.format("/accounts/%s/statuses", accountId), params, new JsonHttpResponseHandler() {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Status status = parseStatuses(response); Status status = parseStatuses(context, response);
statuses.add(status); statuses.add(status);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -365,7 +365,7 @@ public class API {
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
Status status = parseStatuses(response); Status status = parseStatuses(context, response);
statuses.add(status); statuses.add(status);
} }
@Override @Override
@ -445,7 +445,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Status status = parseStatuses(response); Status status = parseStatuses(context, response);
statuses.add(status); statuses.add(status);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -500,7 +500,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Status status = parseStatuses(response); Status status = parseStatuses(context, response);
statuses.add(status); statuses.add(status);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -557,7 +557,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Status status = parseStatuses(response); Status status = parseStatuses(context, response);
statuses.add(status); statuses.add(status);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -641,7 +641,7 @@ public class API {
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
Account account = parseAccountResponse(response); Account account = parseAccountResponse(context, response);
accounts.add(account); accounts.add(account);
} }
@Override @Override
@ -692,7 +692,7 @@ public class API {
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
Account account = parseAccountResponse(response); Account account = parseAccountResponse(context, response);
accounts.add(account); accounts.add(account);
} }
@Override @Override
@ -741,7 +741,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Status status = parseStatuses(response); Status status = parseStatuses(context, response);
statuses.add(status); statuses.add(status);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -945,7 +945,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Status statusreturned = parseStatuses(response); Status statusreturned = parseStatuses(context, response);
statuses.add(statusreturned); statuses.add(statusreturned);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -1041,7 +1041,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Notification notification = parseNotificationResponse(response); Notification notification = parseNotificationResponse(context, response);
notifications.add(notification); notifications.add(notification);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -1118,37 +1118,6 @@ public class API {
return results; return results;
} }
/**
* Retrieves Developer account when searching (ie: via @...) *synchronously*
*
* @return APIResponse
*/
public APIResponse searchDeveloper() {
RequestParams params = new RequestParams();
params.add("q", "tschneider");
get("/accounts/search", params, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
accounts = new ArrayList<>();
account = parseAccountResponse(response);
accounts.add(account);
apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers));
}
@Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
accounts = parseDeveloperResponse(response);
apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers));
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable error, JSONObject response){
setError(statusCode, error);
}
});
apiResponse.setAccounts(accounts);
return apiResponse;
}
/** /**
* Retrieves Accounts when searching (ie: via @...) *synchronously* * Retrieves Accounts when searching (ie: via @...) *synchronously*
* *
@ -1170,7 +1139,7 @@ public class API {
@Override @Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
accounts = new ArrayList<>(); accounts = new ArrayList<>();
account = parseAccountResponse(response); account = parseAccountResponse(context, response);
accounts.add(account); accounts.add(account);
apiResponse.setSince_id(findSinceId(headers)); apiResponse.setSince_id(findSinceId(headers));
apiResponse.setMax_id(findMaxId(headers)); apiResponse.setMax_id(findMaxId(headers));
@ -1236,7 +1205,7 @@ public class API {
while (i < jsonArray.length() ){ while (i < jsonArray.length() ){
JSONObject resobj = jsonArray.getJSONObject(i); JSONObject resobj = jsonArray.getJSONObject(i);
Status status = parseStatuses(resobj); Status status = parseStatuses(context, resobj);
i++; i++;
statuses.add(status); statuses.add(status);
} }
@ -1253,7 +1222,7 @@ public class API {
* @return Status * @return Status
*/ */
@SuppressWarnings("InfiniteRecursion") @SuppressWarnings("InfiniteRecursion")
private Status parseStatuses(JSONObject resobj){ public static Status parseStatuses(Context context, JSONObject resobj){
Status status = new Status(); Status status = new Status();
try { try {
status.setId(resobj.get("id").toString()); status.setId(resobj.get("id").toString());
@ -1315,14 +1284,14 @@ public class API {
} }
status.setTags(tags); status.setTags(tags);
status.setAccount(parseAccountResponse(resobj.getJSONObject("account"))); status.setAccount(parseAccountResponse(context, resobj.getJSONObject("account")));
status.setContent(resobj.get("content").toString()); status.setContent(resobj.get("content").toString());
status.setFavourites_count(Integer.valueOf(resobj.get("favourites_count").toString())); status.setFavourites_count(Integer.valueOf(resobj.get("favourites_count").toString()));
status.setReblogs_count(Integer.valueOf(resobj.get("reblogs_count").toString())); status.setReblogs_count(Integer.valueOf(resobj.get("reblogs_count").toString()));
status.setReblogged(Boolean.valueOf(resobj.get("reblogged").toString())); status.setReblogged(Boolean.valueOf(resobj.get("reblogged").toString()));
status.setFavourited(Boolean.valueOf(resobj.get("favourited").toString())); status.setFavourited(Boolean.valueOf(resobj.get("favourited").toString()));
try{ try{
status.setReblog(parseStatuses(resobj.getJSONObject("reblog"))); status.setReblog(parseStatuses(context, resobj.getJSONObject("reblog")));
}catch (Exception ignored){} }catch (Exception ignored){}
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
@ -1355,7 +1324,7 @@ public class API {
* @param resobj JSONObject * @param resobj JSONObject
* @return Account * @return Account
*/ */
private Account parseAccountResponse(JSONObject resobj){ private static Account parseAccountResponse(Context context, JSONObject resobj){
Account account = new Account(); Account account = new Account();
try { try {
@ -1392,7 +1361,7 @@ public class API {
int i = 0; int i = 0;
while (i < jsonArray.length() ) { while (i < jsonArray.length() ) {
JSONObject resobj = jsonArray.getJSONObject(i); JSONObject resobj = jsonArray.getJSONObject(i);
Account account = parseAccountResponse(resobj); Account account = parseAccountResponse(context, resobj);
accounts.add(account); accounts.add(account);
i++; i++;
} }
@ -1416,7 +1385,7 @@ public class API {
Account account = null; Account account = null;
while (i < jsonArray.length() ) { while (i < jsonArray.length() ) {
JSONObject resobj = jsonArray.getJSONObject(i); JSONObject resobj = jsonArray.getJSONObject(i);
account = parseAccountResponse(resobj); account = parseAccountResponse(context, resobj);
if( account.getAcct().contains(Helper.DEVELOPER_INSTANCE)) if( account.getAcct().contains(Helper.DEVELOPER_INSTANCE))
accounts.add(account); accounts.add(account);
i++; i++;
@ -1500,16 +1469,16 @@ public class API {
* @param resobj JSONObject * @param resobj JSONObject
* @return Account * @return Account
*/ */
private Notification parseNotificationResponse(JSONObject resobj){ public static Notification parseNotificationResponse(Context context, JSONObject resobj){
Notification notification = new Notification(); Notification notification = new Notification();
try { try {
notification.setId(resobj.get("id").toString()); notification.setId(resobj.get("id").toString());
notification.setType(resobj.get("type").toString()); notification.setType(resobj.get("type").toString());
notification.setCreated_at(Helper.mstStringToDate(context, resobj.get("created_at").toString())); notification.setCreated_at(Helper.mstStringToDate(context, resobj.get("created_at").toString()));
notification.setAccount(parseAccountResponse(resobj.getJSONObject("account"))); notification.setAccount(parseAccountResponse(context, resobj.getJSONObject("account")));
try{ try{
notification.setStatus(parseStatuses(resobj.getJSONObject("status"))); notification.setStatus(parseStatuses(context, resobj.getJSONObject("status")));
}catch (Exception ignored){} }catch (Exception ignored){}
notification.setCreated_at(Helper.mstStringToDate(context, resobj.get("created_at").toString())); notification.setCreated_at(Helper.mstStringToDate(context, resobj.get("created_at").toString()));
} catch (JSONException e) { } catch (JSONException e) {
@ -1531,7 +1500,7 @@ public class API {
while (i < jsonArray.length() ) { while (i < jsonArray.length() ) {
JSONObject resobj = jsonArray.getJSONObject(i); JSONObject resobj = jsonArray.getJSONObject(i);
Notification notification = parseNotificationResponse(resobj); Notification notification = parseNotificationResponse(context, resobj);
notifications.add(notification); notifications.add(notification);
i++; i++;
} }

View File

@ -35,6 +35,9 @@ public class Account implements Parcelable {
private int followers_count; private int followers_count;
private int following_count; private int following_count;
private int statuses_count; private int statuses_count;
private String followers_count_str;
private String following_count_str;
private String statuses_count_str;
private String note; private String note;
private String url; private String url;
private String avatar; private String avatar;
@ -43,6 +46,8 @@ public class Account implements Parcelable {
private String header_static; private String header_static;
private String token; private String token;
private String instance; private String instance;
private boolean isFollowing;
private boolean isRemote;
protected Account(Parcel in) { protected Account(Parcel in) {
id = in.readString(); id = in.readString();
@ -237,4 +242,44 @@ public class Account implements Parcelable {
dest.writeString(token); dest.writeString(token);
dest.writeString(instance); dest.writeString(instance);
} }
public boolean isFollowing() {
return isFollowing;
}
public void setFollowing(boolean following) {
isFollowing = following;
}
public boolean isRemote() {
return isRemote;
}
public void setRemote(boolean remote) {
isRemote = remote;
}
public String getFollowers_count_str() {
return followers_count_str;
}
public void setFollowers_count_str(String followers_count_str) {
this.followers_count_str = followers_count_str;
}
public String getFollowing_count_str() {
return following_count_str;
}
public void setFollowing_count_str(String following_count_str) {
this.following_count_str = following_count_str;
}
public String getStatuses_count_str() {
return statuses_count_str;
}
public void setStatuses_count_str(String statuses_count_str) {
this.statuses_count_str = statuses_count_str;
}
} }

View File

@ -15,13 +15,16 @@
package fr.gouv.etalab.mastodon.client.Entities; package fr.gouv.etalab.mastodon.client.Entities;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Date; import java.util.Date;
/** /**
* Created by Thomas on 23/04/2017. * Created by Thomas on 23/04/2017.
*/ */
public class Notification { public class Notification implements Parcelable {
private String id; private String id;
private String type; private String type;
@ -29,6 +32,27 @@ public class Notification {
private Account account; private Account account;
private Status status; private Status status;
protected Notification(Parcel in) {
id = in.readString();
type = in.readString();
account = in.readParcelable(Account.class.getClassLoader());
status = in.readParcelable(Status.class.getClassLoader());
}
public Notification(){};
public static final Creator<Notification> CREATOR = new Creator<Notification>() {
@Override
public Notification createFromParcel(Parcel in) {
return new Notification(in);
}
@Override
public Notification[] newArray(int size) {
return new Notification[size];
}
};
public String getId() { public String getId() {
return id; return id;
} }
@ -68,4 +92,17 @@ public class Notification {
public void setStatus(Status status) { public void setStatus(Status status) {
this.status = status; this.status = status;
} }
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(type);
dest.writeParcelable(account, flags);
dest.writeParcelable(status, flags);
}
} }

View File

@ -55,6 +55,7 @@ public class Status implements Parcelable {
private String language; private String language;
private boolean isTranslated = false; private boolean isTranslated = false;
private boolean isTranslationShown = false; private boolean isTranslationShown = false;
private boolean isNew = false;
protected Status(Parcel in) { protected Status(Parcel in) {
id = in.readString(); id = in.readString();
@ -79,6 +80,7 @@ public class Status implements Parcelable {
spoilerShown = in.readByte() != 0; spoilerShown = in.readByte() != 0;
isTranslated = in.readByte() != 0; isTranslated = in.readByte() != 0;
isTranslationShown = in.readByte() != 0; isTranslationShown = in.readByte() != 0;
isNew = in.readByte() != 0;
} }
public Status(){} public Status(){}
@ -294,6 +296,7 @@ public class Status implements Parcelable {
dest.writeByte((byte) (spoilerShown ? 1 : 0)); dest.writeByte((byte) (spoilerShown ? 1 : 0));
dest.writeByte((byte) (isTranslated ? 1 : 0)); dest.writeByte((byte) (isTranslated ? 1 : 0));
dest.writeByte((byte) (isTranslationShown ? 1 : 0)); dest.writeByte((byte) (isTranslationShown ? 1 : 0));
dest.writeByte((byte) (isNew ? 1 : 0));
} }
public boolean isSpoilerShown() { public boolean isSpoilerShown() {
@ -343,4 +346,12 @@ public class Status implements Parcelable {
public void setReplies(List<Status> replies) { public void setReplies(List<Status> replies) {
this.replies = replies; this.replies = replies;
} }
public boolean isNew() {
return isNew;
}
public void setNew(boolean aNew) {
isNew = aNew;
}
} }

View File

@ -0,0 +1,94 @@
package fr.gouv.etalab.mastodon.client;
import android.annotation.SuppressLint;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* Created by Thomas on 29/08/2017.
*
*/
public class TLSSocketFactory extends SSLSocketFactory {
private final SSLContext sslContext = SSLContext.getInstance("TLS");
public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
X509TrustManager tm = new X509TrustManager() {
@SuppressLint("TrustAllX509TrustManager")
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@SuppressLint("TrustAllX509TrustManager")
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[]{tm}, null);
}
@Override
public String[] getDefaultCipherSuites() {
return sslContext.getSocketFactory().getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return sslContext.getSocketFactory().getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(sslContext.getSocketFactory().createSocket());
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
}

View File

@ -0,0 +1,213 @@
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.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import java.io.File;
import java.util.List;
import fr.gouv.etalab.mastodon.activities.ShowAccountActivity;
import fr.gouv.etalab.mastodon.asynctasks.PostActionAsyncTask;
import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface;
import mastodon.etalab.gouv.fr.mastodon.R;
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
/**
* Created by Thomas on 03/09/2017.
* Adapter for accounts from web
*/
public class AccountSearchDevAdapter extends BaseAdapter implements OnPostActionInterface {
private List<Account> accounts;
private LayoutInflater layoutInflater;
private Context context;
private ViewHolder holder;
public AccountSearchDevAdapter(Context context, List<Account> accounts){
this.context = context;
this.accounts = accounts;
layoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return accounts.size();
}
@Override
public Object getItem(int position) {
return accounts.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ImageLoader imageLoader = ImageLoader.getInstance();
File cacheDir = new File(context.getCacheDir(), context.getString(R.string.app_name));
ImageLoaderConfiguration configImg = new ImageLoaderConfiguration.Builder(context)
.imageDownloader(new PatchBaseImageDownloader(context))
.threadPoolSize(5)
.threadPriority(Thread.MIN_PRIORITY + 3)
.denyCacheImageMultipleSizesInMemory()
.diskCache(new UnlimitedDiskCache(cacheDir))
.build();
if( !imageLoader.isInited())
imageLoader.init(configImg);
DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
final Account account = accounts.get(position);
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.drawer_account_search_dev, parent, false);
holder = new ViewHolder();
holder.account_pp = (ImageView) convertView.findViewById(R.id.account_pp);
holder.account_dn = (TextView) convertView.findViewById(R.id.account_dn);
holder.account_un = (TextView) convertView.findViewById(R.id.account_un);
holder.account_follow = (FloatingActionButton) convertView.findViewById(R.id.account_follow);
holder.acccount_container = (LinearLayout) convertView.findViewById(R.id.acccount_container);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//Redraws icon for locked accounts
final float scale = context.getResources().getDisplayMetrics().density;
if( account != null && account.isLocked()){
Drawable img = ContextCompat.getDrawable(context, R.drawable.ic_action_lock_closed);
img.setBounds(0,0,(int) (20 * scale + 0.5f),(int) (20 * scale + 0.5f));
holder.account_dn.setCompoundDrawables( null, null, img, null);
}else{
holder.account_dn.setCompoundDrawables( null, null, null, null);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
holder.account_dn.setText(Html.fromHtml(Helper.shortnameToUnicode(account.getDisplay_name(), true), Html.FROM_HTML_MODE_LEGACY));
holder.account_un.setText(Html.fromHtml(Helper.shortnameToUnicode(account.getUsername(), true), Html.FROM_HTML_MODE_LEGACY));
}else {
//noinspection deprecation
holder.account_dn.setText(Html.fromHtml(Helper.shortnameToUnicode(account.getDisplay_name(), true)));
holder.account_un.setText(Html.fromHtml(Helper.shortnameToUnicode(account.getUsername(), true)));
}
changeDrawableColor(context, R.drawable.ic_action_lock_closed,R.color.mastodonC4);
//Profile picture
imageLoader.displayImage(account.getAvatar(), holder.account_pp, options);
if( account.isFollowing()){
holder.account_follow.setVisibility(View.GONE);
}else{
holder.account_follow.setVisibility(View.VISIBLE);
}
if( account.isRemote()) {
holder.account_follow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.account_follow.setEnabled(false);
new PostActionAsyncTask(context, API.StatusAction.REMOTE_FOLLOW, account.getAcct(), AccountSearchDevAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
}else {
holder.account_follow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.account_follow.setEnabled(false);
new PostActionAsyncTask(context, API.StatusAction.FOLLOW, account.getId(), AccountSearchDevAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
holder.acccount_container.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, ShowAccountActivity.class);
Bundle b = new Bundle();
b.putString("accountId", account.getId());
intent.putExtras(b);
context.startActivity(intent);
}
});
}
return convertView;
}
@Override
public void onPostAction(int statusCode, API.StatusAction statusAction, String userId, Error error) {
if( error != null){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
if( show_error_messages)
Toast.makeText(context, error.getError(),Toast.LENGTH_LONG).show();
holder.account_follow.setEnabled(true);
return;
}
for( Account account: accounts){
if(account.getId().equals(userId)) {
account.setFollowing(true);
notifyDataSetChanged();
break;
}
}
holder.account_follow.setVisibility(View.GONE);
Toast.makeText(context, R.string.toast_follow, Toast.LENGTH_LONG).show();
}
private class ViewHolder {
LinearLayout acccount_container;
ImageView account_pp;
TextView account_dn;
TextView account_un;
FloatingActionButton account_follow;
}
}

View File

@ -143,9 +143,9 @@ public class AccountSearchWebAdapter extends BaseAdapter implements OnPostAction
} }
changeDrawableColor(context, R.drawable.ic_action_lock_closed,R.color.mastodonC4); changeDrawableColor(context, R.drawable.ic_action_lock_closed,R.color.mastodonC4);
holder.account_ds.setAutoLinkMask(Linkify.WEB_URLS); holder.account_ds.setAutoLinkMask(Linkify.WEB_URLS);
holder.account_sc.setText(String.valueOf(account.getStatuses_count())); holder.account_sc.setText(String.valueOf(account.getStatuses_count_str()));
holder.account_fgc.setText(String.valueOf(account.getFollowing_count())); holder.account_fgc.setText(String.valueOf(account.getFollowing_count_str()));
holder.account_frc.setText(String.valueOf(account.getFollowers_count())); holder.account_frc.setText(String.valueOf(account.getFollowers_count_str()));
//Profile picture //Profile picture
imageLoader.displayImage(account.getAvatar(), holder.account_pp, options); imageLoader.displayImage(account.getAvatar(), holder.account_pp, options);

View File

@ -88,7 +88,7 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
private NotificationsListAdapter notificationsListAdapter; private NotificationsListAdapter notificationsListAdapter;
private int behaviorWithAttachments; private int behaviorWithAttachments;
private boolean isOnWifi; private boolean isOnWifi;
private String targetedId;
public NotificationsListAdapter(Context context, boolean isOnWifi, int behaviorWithAttachments, List<Notification> notifications){ public NotificationsListAdapter(Context context, boolean isOnWifi, int behaviorWithAttachments, List<Notification> notifications){
this.context = context; this.context = context;
@ -170,6 +170,8 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
final float scale = context.getResources().getDisplayMetrics().density; final float scale = context.getResources().getDisplayMetrics().density;
String type = notification.getType(); String type = notification.getType();
String typeString = ""; String typeString = "";
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
Drawable imgH = null;
switch (type){ switch (type){
case "mention": case "mention":
holder.status_action_container.setVisibility(View.VISIBLE); holder.status_action_container.setVisibility(View.VISIBLE);
@ -177,6 +179,12 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_mention)); typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_mention));
else else
typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_mention)); typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_mention));
if( theme == Helper.THEME_DARK){
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_dark_1));
}else {
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_light_1));
}
imgH = null;
break; break;
case "reblog": case "reblog":
holder.status_action_container.setVisibility(View.GONE); holder.status_action_container.setVisibility(View.GONE);
@ -184,6 +192,12 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_reblog)); typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_reblog));
else else
typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_reblog)); typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_reblog));
if( theme == Helper.THEME_DARK){
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_dark_2));
}else {
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_light_2));
}
imgH = ContextCompat.getDrawable(context, R.drawable.ic_retweet_notif_header);
break; break;
case "favourite": case "favourite":
holder.status_action_container.setVisibility(View.GONE); holder.status_action_container.setVisibility(View.GONE);
@ -191,6 +205,12 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_favourite)); typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_favourite));
else else
typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_favourite)); typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_favourite));
if( theme == Helper.THEME_DARK){
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_dark_3));
}else {
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_light_3));
}
imgH = ContextCompat.getDrawable(context, R.drawable.ic_fav_notif_header);
break; break;
case "follow": case "follow":
holder.status_action_container.setVisibility(View.GONE); holder.status_action_container.setVisibility(View.GONE);
@ -198,10 +218,24 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_follow)); typeString = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),context.getString(R.string.notif_follow));
else else
typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_follow)); typeString = String.format("@%s %s", notification.getAccount().getAcct(),context.getString(R.string.notif_follow));
if( theme == Helper.THEME_DARK){
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_dark_4));
}else {
holder.card_status_container.setCardBackgroundColor(ContextCompat.getColor(context, R.color.notif_light_4));
}
imgH = ContextCompat.getDrawable(context, R.drawable.ic_follow_notif_header);
break; break;
} }
changeDrawableColor(context, R.drawable.ic_retweet_notif_header,R.color.mastodonC4);
changeDrawableColor(context, R.drawable.ic_fav_notif_header,R.color.mastodonC4);
changeDrawableColor(context, R.drawable.ic_follow_notif_header,R.color.mastodonC4);
holder.notification_type.setText(typeString); holder.notification_type.setText(typeString);
if( imgH != null) {
holder.notification_type.setCompoundDrawablePadding((int)Helper.convertDpToPixel(5, context));
imgH.setBounds(0, 0, (int) (20 * iconSizePercent / 100 * scale + 0.5f), (int) (20 * iconSizePercent / 100 * scale + 0.5f));
}
holder.notification_type.setCompoundDrawables( imgH, null, null, null);
holder.status_privacy.getLayoutParams().height = (int) Helper.convertDpToPixel((20*iconSizePercent/100), context); holder.status_privacy.getLayoutParams().height = (int) Helper.convertDpToPixel((20*iconSizePercent/100), context);
holder.status_privacy.getLayoutParams().width = (int) Helper.convertDpToPixel((20*iconSizePercent/100), context); holder.status_privacy.getLayoutParams().width = (int) Helper.convertDpToPixel((20*iconSizePercent/100), context);
holder.status_reply.getLayoutParams().height = (int) Helper.convertDpToPixel((20*iconSizePercent/100), context); holder.status_reply.getLayoutParams().height = (int) Helper.convertDpToPixel((20*iconSizePercent/100), context);
@ -214,7 +248,6 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
//Manages theme for icon colors //Manages theme for icon colors
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_DARK){ if( theme == Helper.THEME_DARK){
changeDrawableColor(context, R.drawable.ic_reply,R.color.dark_text); changeDrawableColor(context, R.drawable.ic_reply,R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_action_more,R.color.dark_text); changeDrawableColor(context, R.drawable.ic_action_more,R.color.dark_text);
@ -260,8 +293,13 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
}else{ }else{
holder.notification_account_username.setCompoundDrawables( null, null, null, null); holder.notification_account_username.setCompoundDrawables( null, null, null, null);
} }
String content = status.getContent();
content = content.replaceAll("</p>","<br/><br/>");
content = content.replaceAll("<p>","");
if( content.endsWith("<br/><br/>") )
content = content.substring(0,content.length() -10);
SpannableString spannableString = Helper.clickableElements(context, status.getContent(), SpannableString spannableString = Helper.clickableElements(context, content,
status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), true); status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), true);
holder.notification_status_content.setText(spannableString, TextView.BufferType.SPANNABLE); holder.notification_status_content.setText(spannableString, TextView.BufferType.SPANNABLE);
holder.notification_status_content.setMovementMethod(null); holder.notification_status_content.setMovementMethod(null);
@ -402,7 +440,7 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
@Override @Override
public void onClick(View v) { public void onClick(View v) {
boolean confirmation = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION, true); boolean confirmation = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION_FAV, false);
if( confirmation ) if( confirmation )
displayConfirmationDialog(FAVOURITE,status); displayConfirmationDialog(FAVOURITE,status);
else else
@ -522,7 +560,7 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio
*/ */
private void displayConfirmationNotificationDialog(final Notification notification){ private void displayConfirmationNotificationDialog(final Notification notification){
final ArrayList seletedItems = new ArrayList(); final ArrayList seletedItems = new ArrayList();
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
AlertDialog dialog = new AlertDialog.Builder(context) AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle(R.string.delete_notification_ask) .setTitle(R.string.delete_notification_ask)
.setMultiChoiceItems(new String[]{context.getString(R.string.delete_notification_ask_all)}, null, new DialogInterface.OnMultiChoiceClickListener() { .setMultiChoiceItems(new String[]{context.getString(R.string.delete_notification_ask_all)}, null, new DialogInterface.OnMultiChoiceClickListener() {

View File

@ -14,6 +14,7 @@ package fr.gouv.etalab.mastodon.drawers;
* You should have received a copy of the GNU General Public License along with Mastalab; if not, * You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
import android.graphics.Paint;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
@ -90,6 +91,7 @@ import mastodon.etalab.gouv.fr.mastodon.R;
import static fr.gouv.etalab.mastodon.activities.MainActivity.currentLocale; import static fr.gouv.etalab.mastodon.activities.MainActivity.currentLocale;
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor; import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
import static fr.gouv.etalab.mastodon.helper.Helper.shortnameToUnicode;
/** /**
@ -197,7 +199,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_prev4_container = (RelativeLayout) convertView.findViewById(R.id.status_prev4_container); holder.status_prev4_container = (RelativeLayout) convertView.findViewById(R.id.status_prev4_container);
holder.status_reply = (ImageView) convertView.findViewById(R.id.status_reply); holder.status_reply = (ImageView) convertView.findViewById(R.id.status_reply);
holder.status_privacy = (ImageView) convertView.findViewById(R.id.status_privacy); holder.status_privacy = (ImageView) convertView.findViewById(R.id.status_privacy);
holder.status_translate = (Button) convertView.findViewById(R.id.status_translate); holder.status_translate = (TextView) convertView.findViewById(R.id.status_translate);
holder.status_content_translated_container = (LinearLayout) convertView.findViewById(R.id.status_content_translated_container); holder.status_content_translated_container = (LinearLayout) convertView.findViewById(R.id.status_content_translated_container);
holder.main_container = (LinearLayout) convertView.findViewById(R.id.main_container); holder.main_container = (LinearLayout) convertView.findViewById(R.id.main_container);
holder.status_spoiler_container = (LinearLayout) convertView.findViewById(R.id.status_spoiler_container); holder.status_spoiler_container = (LinearLayout) convertView.findViewById(R.id.status_spoiler_container);
@ -205,9 +207,11 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_spoiler = (TextView) convertView.findViewById(R.id.status_spoiler); holder.status_spoiler = (TextView) convertView.findViewById(R.id.status_spoiler);
holder.status_spoiler_button = (Button) convertView.findViewById(R.id.status_spoiler_button); holder.status_spoiler_button = (Button) convertView.findViewById(R.id.status_spoiler_button);
holder.yandex_translate = (TextView) convertView.findViewById(R.id.yandex_translate); holder.yandex_translate = (TextView) convertView.findViewById(R.id.yandex_translate);
holder.google_translate = (TextView) convertView.findViewById(R.id.google_translate);
holder.status_replies = (LinearLayout) convertView.findViewById(R.id.status_replies); holder.status_replies = (LinearLayout) convertView.findViewById(R.id.status_replies);
holder.status_replies_profile_pictures = (LinearLayout) convertView.findViewById(R.id.status_replies_profile_pictures); holder.status_replies_profile_pictures = (LinearLayout) convertView.findViewById(R.id.status_replies_profile_pictures);
holder.status_replies_text = (TextView) convertView.findViewById(R.id.status_replies_text); holder.status_replies_text = (TextView) convertView.findViewById(R.id.status_replies_text);
holder.new_element = (ImageView) convertView.findViewById(R.id.new_element);
convertView.setTag(holder); convertView.setTag(holder);
} else { } else {
holder = (ViewHolder) convertView.getTag(); holder = (ViewHolder) convertView.getTag();
@ -217,7 +221,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
//Display a preview for accounts that have replied *if enabled and only for home timeline* //Display a preview for accounts that have replied *if enabled and only for home timeline*
if( type == RetrieveFeedsAsyncTask.Type.HOME ) { if( type == RetrieveFeedsAsyncTask.Type.HOME ) {
boolean showPreview = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, true); boolean showPreview = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, false);
if( showPreview){ if( showPreview){
boolean showPreviewPP = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES_PP, true); boolean showPreviewPP = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES_PP, true);
if( status.getReplies() == null){ if( status.getReplies() == null){
@ -259,6 +263,11 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
} }
} }
changeDrawableColor(context, R.drawable.ic_fiber_new,R.color.mastodonC4);
if( status.isNew())
holder.new_element.setVisibility(View.VISIBLE);
else
holder.new_element.setVisibility(View.GONE);
int iconSizePercent = sharedpreferences.getInt(Helper.SET_ICON_SIZE, 130); int iconSizePercent = sharedpreferences.getInt(Helper.SET_ICON_SIZE, 130);
int textSizePercent = sharedpreferences.getInt(Helper.SET_TEXT_SIZE, 110); int textSizePercent = sharedpreferences.getInt(Helper.SET_TEXT_SIZE, 110);
@ -301,6 +310,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
statusListAdapter.notifyDataSetChanged(); statusListAdapter.notifyDataSetChanged();
} }
}); });
holder.status_translate.setPaintFlags(holder.status_translate.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
if( currentLocale != null && status.getLanguage() != null && !status.getLanguage().trim().equals(currentLocale) && !status.getLanguage().trim().equals("null")){ if( currentLocale != null && status.getLanguage() != null && !status.getLanguage().trim().equals(currentLocale) && !status.getLanguage().trim().equals("null")){
if (translator != Helper.TRANS_NONE) if (translator != Helper.TRANS_NONE)
holder.status_translate.setVisibility(View.VISIBLE); holder.status_translate.setVisibility(View.VISIBLE);
@ -310,10 +320,25 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_translate.setVisibility(View.GONE); holder.status_translate.setVisibility(View.GONE);
} }
if( translator == Helper.TRANS_YANDEX) switch (translator)
holder.yandex_translate.setVisibility(View.VISIBLE); {
else case Helper.TRANS_NONE:
holder.yandex_translate.setVisibility(View.GONE); holder.yandex_translate.setVisibility(View.GONE);
holder.google_translate.setVisibility(View.GONE);
break;
case Helper.TRANS_YANDEX:
holder.google_translate.setVisibility(View.GONE);
holder.yandex_translate.setVisibility(View.VISIBLE);
break;
case Helper.TRANS_GOOGLE:
holder.yandex_translate.setVisibility(View.GONE);
holder.google_translate.setVisibility(View.VISIBLE);
break;
default:
holder.yandex_translate.setVisibility(View.GONE);
holder.google_translate.setVisibility(View.GONE);
break;
}
holder.status_translate.setOnClickListener(new View.OnClickListener() { holder.status_translate.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -340,6 +365,11 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
while (matcher.find()){ while (matcher.find()){
String key = "__u" + String.valueOf(i) + "__"; String key = "__u" + String.valueOf(i) + "__";
String value = matcher.group(0); String value = matcher.group(0);
int end = matcher.end();
if (spannableString.charAt(end) == '/') {
text = spannableString.toString().substring(0, end).
concat(spannableString.toString().substring(end+1, spannableString.length()));
}
if( value != null) { if( value != null) {
urlConversion.put(key, value); urlConversion.put(key, value);
text = text.replace(value, key); text = text.replace(value, key);
@ -361,9 +391,13 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
} }
if (translator == Helper.TRANS_YANDEX) if (translator == Helper.TRANS_YANDEX)
new YandexQuery(StatusListAdapter.this).getYandexTextview(position, text, currentLocale); new YandexQuery(StatusListAdapter.this).getYandexTextview(position, text, currentLocale);
else if( translator == Helper.TRANS_GOOGLE) else if( translator == Helper.TRANS_GOOGLE) {
new GoogleTranslateQuery(StatusListAdapter.this).getGoogleTextview(position, text, currentLocale);
while( text.charAt(text.length() -1) == '\n' && text.length() > 0)
text = text.substring(0, text.length() -1);
text += ".";
new GoogleTranslateQuery(StatusListAdapter.this).getGoogleTextview(position, text.trim(), currentLocale);
}
}else { }else {
status.setTranslationShown(!status.isTranslationShown()); status.setTranslationShown(!status.isTranslationShown());
statusListAdapter.notifyDataSetChanged(); statusListAdapter.notifyDataSetChanged();
@ -381,6 +415,13 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
context.startActivity(browserIntent); context.startActivity(browserIntent);
} }
}); });
holder.google_translate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://translate.google.com/"));
context.startActivity(browserIntent);
}
});
//Toot was translated and user asked to see it //Toot was translated and user asked to see it
if( status.isTranslationShown()){ if( status.isTranslationShown()){
holder.status_content.setVisibility(View.GONE); holder.status_content.setVisibility(View.GONE);
@ -480,7 +521,10 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
} }
} }
final String content, displayName, username, ppurl; String content;
final String displayName;
final String username;
final String ppurl;
if( status.getReblog() != null){ if( status.getReblog() != null){
content = status.getReblog().getContent(); content = status.getReblog().getContent();
displayName = Helper.shortnameToUnicode(status.getReblog().getAccount().getDisplay_name(), true); displayName = Helper.shortnameToUnicode(status.getReblog().getAccount().getDisplay_name(), true);
@ -546,7 +590,10 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
}); });
holder.status_content_translated.setMovementMethod(LinkMovementMethod.getInstance()); holder.status_content_translated.setMovementMethod(LinkMovementMethod.getInstance());
} }
content = content.replaceAll("</p>","<br/><br/>");
content = content.replaceAll("<p>","");
if( content.endsWith("<br/><br/>") )
content = content.substring(0,content.length() -10);
final SpannableString spannableString = Helper.clickableElements(context,content, final SpannableString spannableString = Helper.clickableElements(context,content,
status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), true); status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), true);
holder.status_content.setText(spannableString, TextView.BufferType.SPANNABLE); holder.status_content.setText(spannableString, TextView.BufferType.SPANNABLE);
@ -712,7 +759,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
@Override @Override
public void onClick(View v) { public void onClick(View v) {
boolean confirmation = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION, true); boolean confirmation = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION_FAV, false);
if( confirmation ) if( confirmation )
displayConfirmationDialog(FAVOURITE,status); displayConfirmationDialog(FAVOURITE,status);
else else
@ -956,6 +1003,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
statuses.get(position).setContent_translated(aJsonString); statuses.get(position).setContent_translated(aJsonString);
statusListAdapter.notifyDataSetChanged(); statusListAdapter.notifyDataSetChanged();
} catch (JSONException | UnsupportedEncodingException | IllegalArgumentException e) { } catch (JSONException | UnsupportedEncodingException | IllegalArgumentException e) {
e.printStackTrace();
Toast.makeText(context, R.string.toast_error_translate, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.toast_error_translate, Toast.LENGTH_LONG).show();
} }
} }
@ -965,6 +1013,16 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
JSONObject translationJson = new JSONObject(text); JSONObject translationJson = new JSONObject(text);
JSONArray aJsonArray = translationJson.getJSONArray("text"); JSONArray aJsonArray = translationJson.getJSONArray("text");
String aJsonString = aJsonArray.get(0).toString(); String aJsonString = aJsonArray.get(0).toString();
/* The one instance where I've seen this happen,
the special tag was originally a hashtag ("__t1__"),
that Yandex decided to change to a "__q1 - __".
*/
aJsonString = aJsonString.replaceAll("__q(\\d+) - __", "__t$1__");
// Noticed this in the very same toot
aJsonString = aJsonString.replace("&amp;", "&");
aJsonString = URLDecoder.decode(aJsonString, "UTF-8"); aJsonString = URLDecoder.decode(aJsonString, "UTF-8");
return aJsonString; return aJsonString;
} }
@ -988,6 +1046,19 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
aJsonString = aJsonString.replace(" //","//"); aJsonString = aJsonString.replace(" //","//");
aJsonString = aJsonString.replace(" www .","www."); aJsonString = aJsonString.replace(" www .","www.");
aJsonString = aJsonString.replace("www .","www."); aJsonString = aJsonString.replace("www .","www.");
// This one might cause more trouble than it's worth
aJsonString = aJsonString.replaceAll("\\* \\.", "*.");
/*
Noticed that sometimes the special tags were getting messed up by Google,
might be other variants, only caught one so far.
But, pre-planning might save some time later...
*/
aJsonString = aJsonString.replaceAll("__\\s?(u|t)\\s?(\\d+)\\s?__", "__$1$2__");
aJsonString = aJsonString.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
aJsonString = aJsonString.replaceAll("\\+", "%2B");
aJsonString = URLDecoder.decode(aJsonString, "UTF-8"); aJsonString = URLDecoder.decode(aJsonString, "UTF-8");
return aJsonString; return aJsonString;
} }
@ -1026,16 +1097,19 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
RelativeLayout status_prev4_container; RelativeLayout status_prev4_container;
ImageView status_reply; ImageView status_reply;
ImageView status_privacy; ImageView status_privacy;
Button status_translate; TextView status_translate;
LinearLayout status_container2; LinearLayout status_container2;
LinearLayout status_container3; LinearLayout status_container3;
LinearLayout main_container; LinearLayout main_container;
TextView yandex_translate; TextView yandex_translate;
TextView google_translate;
LinearLayout status_replies; LinearLayout status_replies;
LinearLayout status_replies_profile_pictures; LinearLayout status_replies_profile_pictures;
TextView status_replies_text; TextView status_replies_text;
LinearLayout loader_replies; LinearLayout loader_replies;
ImageView new_element;
} }

View File

@ -31,13 +31,14 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.activities.MainActivity;
import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.drawers.NotificationsListAdapter; import fr.gouv.etalab.mastodon.drawers.NotificationsListAdapter;
import fr.gouv.etalab.mastodon.drawers.StatusListAdapter;
import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite; import fr.gouv.etalab.mastodon.sqlite.Sqlite;
@ -66,12 +67,9 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve
private SwipeRefreshLayout swipeRefreshLayout; private SwipeRefreshLayout swipeRefreshLayout;
private boolean swiped; private boolean swiped;
private ListView lv_notifications; private ListView lv_notifications;
private DisplayNotificationsFragment displayNotificationsFragment;
private TextView new_data; private TextView new_data;
private String since_id;
public DisplayNotificationsFragment(){ public DisplayNotificationsFragment(){
displayNotificationsFragment = this;
} }
@Override @Override
@ -138,27 +136,28 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve
new_data.setOnClickListener(new View.OnClickListener() { new_data.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
notificationsTmp = Helper.getTempNotification(context, null);
if( notificationsTmp != null){ if( notificationsTmp != null){
for(int i = notificationsTmp.size() -1 ; i >= 0 ; i--){
notifications.add(0,notificationsTmp.get(i));
}
boolean isOnWifi = Helper.isOnWIFI(context); boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
notifications = new ArrayList<>();
for(Notification notification: notificationsTmp){
notifications.add(notification);
}
//The user clicked on the banner to refresh values so, the pointer is changed
if( notificationsTmp.size() > 0 ) {
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, notificationsTmp.get(0).getId());
editor.apply();
}
notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications); notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications);
lv_notifications.setAdapter(notificationsListAdapter); lv_notifications.setAdapter(notificationsListAdapter);
if( notificationsTmp.size() > 0){
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, notificationsTmp.get(0).getId());
editor.apply();
}
if( notificationsTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE) if( notificationsTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE); textviewNoAction.setVisibility(View.GONE);
} }
new_data.setVisibility(View.GONE); new_data.setVisibility(View.GONE);
notificationsTmp = new ArrayList<>(); notificationsTmp = new ArrayList<>();
Helper.cacheNotificationsClear(context, null);
((MainActivity) context).updateNotifCounter();
} }
}); });
@ -188,11 +187,42 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve
} }
@Override
public void onResume() {
super.onResume();
//New data are available
notificationsTmp = Helper.getTempNotification(context, null);
if (getUserVisibleHint() && notificationsTmp != null && notificationsTmp.size() > 0 && notifications.size() > 0) {
ArrayList<String> added = new ArrayList<>();
for(Notification notification : notifications){
added.add(notification.getId());
}
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
for(int i = notificationsTmp.size() -1 ; i >= 0 ; i--){
if( !added.contains(notificationsTmp.get(i).getId())) {
this.notifications.add(0, notificationsTmp.get(i));
added.add(notificationsTmp.get(i).getId());
}
}
if( this.notifications.size() > 0 )
max_id = this.notifications.get(this.notifications.size()-1).getId();
notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications);
lv_notifications.setAdapter(notificationsListAdapter);
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if( isVisibleToUser )
refresh();
}
@Override @Override
public void onRetrieveNotifications(APIResponse apiResponse, String acct, String userId, boolean refreshData) { public void onRetrieveNotifications(APIResponse apiResponse, String acct, String userId, boolean refreshData) {
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
//UserId will be null here, so it needs to be retrieved from shared preferences
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
mainLoader.setVisibility(View.GONE); mainLoader.setVisibility(View.GONE);
nextElementLoader.setVisibility(View.GONE); nextElementLoader.setVisibility(View.GONE);
if( apiResponse.getError() != null){ if( apiResponse.getError() != null){
@ -205,78 +235,34 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve
return; return;
} }
SharedPreferences.Editor editor = sharedpreferences.edit(); SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ userId,Helper.dateToString(context, new Date()));
editor.apply();
String bubble_max_id = sharedpreferences.getString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, null);
List<Notification> notifications = apiResponse.getNotifications(); List<Notification> notifications = apiResponse.getNotifications();
since_id = apiResponse.getSince_id(); String since_id = apiResponse.getSince_id();
max_id = apiResponse.getMax_id(); max_id = apiResponse.getMax_id();
//The initial call comes from a classic tab refresh //The initial call comes from a classic tab refresh
if( refreshData ) {
manageNotifications(notifications, max_id, since_id);
//The current tab is displayed, so user is supposed to have seen the notifications
if( since_id != null && displayNotificationsFragment.getUserVisibleHint()) {
editor.putString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, since_id);
editor.apply();
}else if(!displayNotificationsFragment.getUserVisibleHint()){
//The refresh was done automatically, but the fragment was not displayed in viewpager
//So the bubble counter will be displayed
int countData = 0;
//Retrieves new notification count
if( bubble_max_id != null) {
for (Notification nt : notifications) {
if (nt.getId().trim().equals(bubble_max_id.trim()))
break;
countData++;
}
}
((MainActivity)context).updateNotifCounter(countData);
}
}else { //Here, new values have been retrieved on the onResume call (forced mode)
int countData = 0;
if( bubble_max_id != null) {
for (Notification nt : notifications) {
if (nt.getId().trim().equals(bubble_max_id.trim()))
break;
countData++;
}
}
if( notifications != null && notifications.size() > 0 && countData > 0) {
max_id = null;
firstLoad = true;
notificationsTmp = new ArrayList<>();
for (Notification tmpNotification : notifications) {
this.notificationsTmp.add(tmpNotification);
}
//New notifications will be counted
//The fragment is not displayed, so the bubble counter should be shown
if (!displayNotificationsFragment.getUserVisibleHint()) {
((MainActivity) context).updateNotifCounter(countData);
} else { //The current fragment is visible, but for avoiding to populate with new values
// a message will be displayed at the bottom requiring a click to display these new values
new_data.setVisibility(View.VISIBLE);
}
}
}
}
private void manageNotifications(List<Notification> notifications, String max_id, String since_id){
flag_loading = (max_id == null ); flag_loading = (max_id == null );
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( !swiped && firstLoad && (notifications == null || notifications.size() == 0)) if( !swiped && firstLoad && (notifications == null || notifications.size() == 0))
textviewNoAction.setVisibility(View.VISIBLE); textviewNoAction.setVisibility(View.VISIBLE);
else else
textviewNoAction.setVisibility(View.GONE); textviewNoAction.setVisibility(View.GONE);
if( swiped ){ if( swiped ){
Helper.cacheNotificationsClear(context,null);
((MainActivity) context).updateNotifCounter();
boolean isOnWifi = Helper.isOnWIFI(context); boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, this.notifications); notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, this.notifications);
lv_notifications.setAdapter(notificationsListAdapter); lv_notifications.setAdapter(notificationsListAdapter);
swiped = false; swiped = false;
} }
ArrayList<String> added = new ArrayList<>();
for(Notification notification : this.notifications){
added.add(notification.getId());
}
if( notifications != null && notifications.size() > 0) { if( notifications != null && notifications.size() > 0) {
for(Notification tmpNotification: notifications){ for(Notification tmpNotification: notifications){
this.notifications.add(tmpNotification); if( !added.contains(tmpNotification.getId())) {
this.notifications.add(tmpNotification);
added.add(tmpNotification.getId());
}
} }
notificationsListAdapter.notifyDataSetChanged(); notificationsListAdapter.notifyDataSetChanged();
} }
@ -284,52 +270,57 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve
//Store last notification id to avoid to notify for those that have been already seen //Store last notification id to avoid to notify for those that have been already seen
if( notifications != null && notifications.size() > 0) { if( notifications != null && notifications.size() > 0) {
//acct is null as userId when used in Fragment, data need to be retrieved via shared preferences and db //acct is null as userId when used in Fragment, data need to be retrieved via shared preferences and db
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account currentAccount = new AccountDAO(context, db).getAccountByID(userId); Account currentAccount = new AccountDAO(context, db).getAccountByID(userId);
if( currentAccount != null && firstLoad && since_id != null){ if( currentAccount != null && firstLoad && since_id != null){
SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + currentAccount.getId(), notifications.get(0).getId());
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + currentAccount.getId(), since_id);
editor.apply(); editor.apply();
} }
} }
firstLoad = false; firstLoad = false;
} }
public void scrollToTop(){ public void scrollToTop(){
if( lv_notifications != null) if( lv_notifications != null)
lv_notifications.setAdapter(notificationsListAdapter); lv_notifications.setAdapter(notificationsListAdapter);
} }
public void update(){
if( context != null){ public void showNewContent(){
asyncTask = new RetrieveNotificationsAsyncTask(context, null, null, null, null, null, false, DisplayNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new_data.setVisibility(View.VISIBLE);
}
public void refresh(){
if( context == null)
return;
notificationsTmp = Helper.getTempNotification(context, null);
if( notificationsTmp.size() > 0){
ArrayList<String> added = new ArrayList<>();
for(Notification notification : notifications){
added.add(notification.getId());
}
for(int i = notificationsTmp.size() -1 ; i >= 0 ; i--){
if( !added.contains(notificationsTmp.get(i).getId())) {
this.notifications.add(0, notificationsTmp.get(i));
added.add(notificationsTmp.get(i).getId());
}
}
if( this.notifications.size() > 0 )
max_id = this.notifications.get(this.notifications.size()-1).getId();
boolean isOnWifi = Helper.isOnWIFI(context);
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, notificationsTmp.get(0).getId());
editor.apply();
notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications);
lv_notifications.setAdapter(notificationsListAdapter);
if( textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE);
} }
} new_data.setVisibility(View.GONE);
}
public void refreshData(){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if(context != null && this.notificationsTmp != null && this.notificationsTmp.size() > 0){
boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
notifications = new ArrayList<>();
for(Notification notification: this.notificationsTmp){
notifications.add(notification);
}
if( textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE);
notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications);
lv_notifications.setAdapter(notificationsListAdapter);
this.notificationsTmp = new ArrayList<>();
}
if( since_id != null){
//The user clicked on the tab to refresh values so, the pointer is changed
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, since_id);
editor.apply();
}
}
} }

View File

@ -25,6 +25,7 @@ import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -75,20 +76,16 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
private boolean isOnWifi; private boolean isOnWifi;
private int behaviorWithAttachments; private int behaviorWithAttachments;
private boolean showMediaOnly; private boolean showMediaOnly;
private DisplayStatusFragment displayStatusFragment;
private TextView new_data; private TextView new_data;
private int positionSpinnerTrans; private int positionSpinnerTrans;
private String since_id;
private boolean hideHeader; private boolean hideHeader;
private String instanceValue; private String instanceValue;
public DisplayStatusFragment(){ public DisplayStatusFragment(){
displayStatusFragment = this;
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_status, container, false); View rootView = inflater.inflate(R.layout.fragment_status, container, false);
statuses = new ArrayList<>(); statuses = new ArrayList<>();
context = getContext(); context = getContext();
@ -204,7 +201,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
R.color.mastodonC2, R.color.mastodonC2,
R.color.mastodonC3); R.color.mastodonC3);
if( type == RetrieveFeedsAsyncTask.Type.USER) if( type == RetrieveFeedsAsyncTask.Type.USER)
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else if( type == RetrieveFeedsAsyncTask.Type.TAG) else if( type == RetrieveFeedsAsyncTask.Type.TAG)
@ -222,27 +218,29 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
new_data.setOnClickListener(new View.OnClickListener() { new_data.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
statusesTmp = Helper.getTempStatus(context, null);
if( statusesTmp != null){ if( statusesTmp != null){
for(int i = statusesTmp.size() -1 ; i >= 0 ; i--){
statuses.add(0,statusesTmp.get(i));
}
boolean isOnWifi = Helper.isOnWIFI(context); boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
statuses = new ArrayList<>(); statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses);
for(Status status: statusesTmp){ lv_status.setAdapter(statusListAdapter);
statuses.add(status); if( statusesTmp.size() > 0){
}
//The user clicked on the banner to refresh values so, the pointer is changed
if( statusesTmp.size() > 0 ) {
SharedPreferences.Editor editor = sharedpreferences.edit(); SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, statusesTmp.get(0).getId()); editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, statusesTmp.get(0).getId());
editor.apply(); editor.apply();
} }
if( statusesTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE) if( statusesTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE); textviewNoAction.setVisibility(View.GONE);
statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses);
lv_status.setAdapter(statusListAdapter);
statusesTmp = new ArrayList<>();
} }
new_data.setVisibility(View.GONE); new_data.setVisibility(View.GONE);
statusesTmp = new ArrayList<>();
Helper.cacheStatusClear(context, null);
((MainActivity) context).updateHomeCounter();
} }
}); });
@ -261,24 +259,29 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
//New data are available if( type == RetrieveFeedsAsyncTask.Type.HOME ) {
if (getUserVisibleHint() && statusesTmp != null && statusesTmp.size() > 0 ) { //New data are available
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); statusesTmp = Helper.getTempStatus(context, null);
boolean isOnWifi = Helper.isOnWIFI(context); if (getUserVisibleHint() && statusesTmp != null && statusesTmp.size() > 0 && statuses.size() > 0) {
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); ArrayList<String> added = new ArrayList<>();
int positionSpinnerTrans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_YANDEX); for (Status status : statuses) {
statuses = new ArrayList<>(); added.add(status.getId());
for(Status status: statusesTmp){ }
statuses.add(status); final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
int positionSpinnerTrans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_YANDEX);
for (int i = statusesTmp.size() - 1; i >= 0; i--) {
if (!added.contains(statusesTmp.get(i).getId())) {
this.statuses.add(0, statusesTmp.get(i));
added.add(statusesTmp.get(i).getId());
}
}
if (this.statuses.size() > 0)
max_id = this.statuses.get(this.statuses.size() - 1).getId();
statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses);
lv_status.setAdapter(statusListAdapter);
} }
//The user clicked on the tab to refresh values so, the pointer is changed
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, statusesTmp.get(0).getId());
editor.apply();
statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses);
lv_status.setAdapter(statusListAdapter);
statusesTmp = new ArrayList<>();
} }
} }
@ -313,87 +316,33 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
return; return;
} }
List<Status> statuses = apiResponse.getStatuses(); List<Status> statuses = apiResponse.getStatuses();
since_id = apiResponse.getSince_id(); String since_id = apiResponse.getSince_id();
max_id = apiResponse.getMax_id(); max_id = apiResponse.getMax_id();
//Special case for home timeline
if( type == RetrieveFeedsAsyncTask.Type.HOME){
//Retrieves some values
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String bubble_max_id = sharedpreferences.getString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, null);
//The initial call comes from a classic tab refresh
if( refreshData ) {
manageStatus(statuses, max_id, since_id);
//The current tab is displayed, so user is supposed to have seen status
if( since_id != null && displayStatusFragment.getUserVisibleHint()) {
editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, since_id);
editor.apply();
}else if(!displayStatusFragment.getUserVisibleHint()){
//Current fragment was loaded but not displayed to the user.
//So the bubble counter will be displayed
int countData = 0;
//Retrieves new status count
if( bubble_max_id != null) {
for (Status st : statuses) {
if (st.getId().trim().equals(bubble_max_id.trim()))
break;
countData++;
}
}
((MainActivity)context).updateHomeCounter(countData);
}
}else { //Here, new values have been retrieved on the onResume call (forced mode)
int countData = 0;
if( bubble_max_id != null) {
for (Status st : statuses) {
if (st.getId().trim().equals(bubble_max_id.trim()))
break;
countData++;
}
}
if( statuses != null && statuses.size() > 0 && countData > 0) {
max_id = null;
firstLoad = true;
statusesTmp = new ArrayList<>();
for (Status tmpStatus : statuses) {
this.statusesTmp.add(tmpStatus);
}
//New status will be counted
//The fragment is not displayed, so the bubble counter should be shown
if (!displayStatusFragment.getUserVisibleHint()) {
((MainActivity) context).updateHomeCounter(countData);
} else {
//The current fragment is visible, but for avoiding to populate with new values
//Values are put in temp and the banned is displayed
new_data.setVisibility(View.VISIBLE);
}
}
}
}else {
manageStatus(statuses, max_id, since_id);
}
}
private void manageStatus(List<Status> statuses, String max_id, String since_id){
flag_loading = (max_id == null ); flag_loading = (max_id == null );
if( !swiped && firstLoad && (statuses == null || statuses.size() == 0)) if( !swiped && firstLoad && (statuses == null || statuses.size() == 0))
textviewNoAction.setVisibility(View.VISIBLE); textviewNoAction.setVisibility(View.VISIBLE);
else else
textviewNoAction.setVisibility(View.GONE); textviewNoAction.setVisibility(View.GONE);
if( swiped ){ if( swiped ){
if( type == RetrieveFeedsAsyncTask.Type.HOME ) {
Helper.cacheStatusClear(context,null);
((MainActivity) context).updateHomeCounter();
}
statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, this.statuses); statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, this.statuses);
lv_status.setAdapter(statusListAdapter); lv_status.setAdapter(statusListAdapter);
swiped = false; swiped = false;
} }
ArrayList<String> added = new ArrayList<>();
for(Status status : this.statuses){
added.add(status.getId());
}
if( statuses != null && statuses.size() > 0) { if( statuses != null && statuses.size() > 0) {
for(Status tmpStatus: statuses){ for(Status tmpStatus: statuses){
this.statuses.add(tmpStatus); if( !added.contains(tmpStatus.getId())) {
this.statuses.add(tmpStatus);
added.add(tmpStatus.getId());
}
} }
statusListAdapter.notifyDataSetChanged(); statusListAdapter.notifyDataSetChanged();
} }
@ -401,14 +350,13 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
//Store last toot id for home timeline to avoid to notify for those that have been already seen //Store last toot id for home timeline to avoid to notify for those that have been already seen
if(statuses != null && statuses.size() > 0 && type == RetrieveFeedsAsyncTask.Type.HOME ){ if(statuses != null && statuses.size() > 0 && type == RetrieveFeedsAsyncTask.Type.HOME ){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
//acct is null when used in Fragment, data need to be retrieved via shared preferences and db //acct is null when used in Fragment, data need to be retrieved via shared preferences and db
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account currentAccount = new AccountDAO(context, db).getAccountByID(userId); Account currentAccount = new AccountDAO(context, db).getAccountByID(userId);
if( currentAccount != null && firstLoad && since_id != null){ if( currentAccount != null && firstLoad && since_id != null){
SharedPreferences.Editor editor = sharedpreferences.edit(); SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + currentAccount.getId(), since_id); editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + currentAccount.getId(), statuses.get(0).getId());
editor.apply(); editor.apply();
} }
} }
@ -416,8 +364,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
//Retrieves replies //Retrieves replies
if(statuses != null && statuses.size() > 0 && type == RetrieveFeedsAsyncTask.Type.HOME ) { if(statuses != null && statuses.size() > 0 && type == RetrieveFeedsAsyncTask.Type.HOME ) {
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); boolean showPreview = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, false);
boolean showPreview = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, true);
//Retrieves attached replies to a toot //Retrieves attached replies to a toot
if (showPreview) { if (showPreview) {
new RetrieveRepliesAsyncTask(context, statuses, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new RetrieveRepliesAsyncTask(context, statuses, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ -425,6 +372,52 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
} }
} }
public void showNewContent(){
new_data.setVisibility(View.VISIBLE);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if( isVisibleToUser )
refresh();
}
public void refresh(){
//New data are available
if( type == RetrieveFeedsAsyncTask.Type.HOME ) {
if (context == null)
return;
statusesTmp = Helper.getTempStatus(context, null);
if (statusesTmp.size() > 0) {
ArrayList<String> added = new ArrayList<>();
for (Status status : statuses) {
added.add(status.getId());
}
for (int i = statusesTmp.size() - 1; i >= 0; i--) {
if (!added.contains(statusesTmp.get(i).getId())) {
this.statuses.add(0, statusesTmp.get(i));
added.add(statusesTmp.get(i).getId());
}
}
if (this.statuses.size() > 0)
max_id = this.statuses.get(this.statuses.size() - 1).getId();
boolean isOnWifi = Helper.isOnWIFI(context);
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, statusesTmp.get(0).getId());
editor.apply();
statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses);
lv_status.setAdapter(statusListAdapter);
if (textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE);
}
new_data.setVisibility(View.GONE);
}
}
public void scrollToTop(){ public void scrollToTop(){
if( lv_status != null) if( lv_status != null)
lv_status.setAdapter(statusListAdapter); lv_status.setAdapter(statusListAdapter);
@ -444,36 +437,4 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
} }
statusListAdapter.notifyDataSetChanged(); statusListAdapter.notifyDataSetChanged();
} }
public void update() {
if( context != null) {
asyncTask = new RetrieveFeedsAsyncTask(context, type, null, false, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
public void refreshData(){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if(context != null && this.statusesTmp != null && this.statusesTmp.size() > 0){
boolean isOnWifi = Helper.isOnWIFI(context);
int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS);
int positionSpinnerTrans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_YANDEX);
statuses = new ArrayList<>();
for(Status status: statusesTmp){
statuses.add(status);
}
if( textviewNoAction.getVisibility() == View.VISIBLE)
textviewNoAction.setVisibility(View.GONE);
statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses);
lv_status.setAdapter(statusListAdapter);
statusesTmp = new ArrayList<>();
}
if( since_id != null){
//The user clicked on the tab to refresh values so, the pointer is changed
SharedPreferences.Editor editor = sharedpreferences.edit();
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, since_id);
editor.apply();
}
}
} }

View File

@ -94,19 +94,6 @@ public class SettingsFragment extends Fragment {
} }
}); });
boolean bubble_counter = sharedpreferences.getBoolean(Helper.SET_BUBBLE_COUNTER, true);
final CheckBox set_bubble_counter = (CheckBox) rootView.findViewById(R.id.set_bubble_counter);
set_bubble_counter.setChecked(bubble_counter);
set_bubble_counter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_BUBBLE_COUNTER, set_bubble_counter.isChecked());
editor.apply();
}
});
boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true); boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
final CheckBox set_show_error_messages = (CheckBox) rootView.findViewById(R.id.set_show_error_messages); final CheckBox set_show_error_messages = (CheckBox) rootView.findViewById(R.id.set_show_error_messages);
set_show_error_messages.setChecked(show_error_messages); set_show_error_messages.setChecked(show_error_messages);
@ -133,7 +120,7 @@ public class SettingsFragment extends Fragment {
} }
}); });
boolean preview_reply = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, true); boolean preview_reply = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, false);
final CheckBox set_preview_reply = (CheckBox) rootView.findViewById(R.id.set_preview_reply); final CheckBox set_preview_reply = (CheckBox) rootView.findViewById(R.id.set_preview_reply);
final LinearLayout set_preview_reply_pp_container = (LinearLayout) rootView.findViewById(R.id.set_preview_reply_pp_container); final LinearLayout set_preview_reply_pp_container = (LinearLayout) rootView.findViewById(R.id.set_preview_reply_pp_container);
final SwitchCompat set_preview_reply_pp = (SwitchCompat) rootView.findViewById(R.id.set_preview_reply_pp); final SwitchCompat set_preview_reply_pp = (SwitchCompat) rootView.findViewById(R.id.set_preview_reply_pp);
@ -152,6 +139,7 @@ public class SettingsFragment extends Fragment {
} }
} }
}); });
if( !preview_reply){ if( !preview_reply){
set_preview_reply_pp_container.setVisibility(View.GONE); set_preview_reply_pp_container.setVisibility(View.GONE);
}else{ }else{
@ -181,6 +169,53 @@ public class SettingsFragment extends Fragment {
} }
}); });
boolean notif_validation_fav = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION_FAV, false);
final CheckBox set_share_validation_fav = (CheckBox) rootView.findViewById(R.id.set_share_validation_fav);
set_share_validation_fav.setChecked(notif_validation_fav);
set_share_validation_fav.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_NOTIF_VALIDATION_FAV, set_share_validation_fav.isChecked());
editor.apply();
}
});
boolean display_local = sharedpreferences.getBoolean(Helper.SET_DISPLAY_LOCAL, true);
final CheckBox set_display_local = (CheckBox) rootView.findViewById(R.id.set_display_local);
set_display_local.setChecked(display_local);
set_display_local.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_DISPLAY_LOCAL, set_display_local.isChecked());
editor.apply();
getActivity().recreate();
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(INTENT_ACTION, CHANGE_THEME_INTENT);
startActivity(intent);
}
});
boolean display_global = sharedpreferences.getBoolean(Helper.SET_DISPLAY_GLOBAL, true);
final CheckBox set_display_global = (CheckBox) rootView.findViewById(R.id.set_display_global);
set_display_global.setChecked(display_global);
set_display_global.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_DISPLAY_GLOBAL, set_display_global.isChecked());
editor.apply();
getActivity().recreate();
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(INTENT_ACTION, CHANGE_THEME_INTENT);
startActivity(intent);
}
});
final CheckBox set_embedded_browser = (CheckBox) rootView.findViewById(R.id.set_embedded_browser); final CheckBox set_embedded_browser = (CheckBox) rootView.findViewById(R.id.set_embedded_browser);
final LinearLayout set_javascript_container = (LinearLayout) rootView.findViewById(R.id.set_javascript_container); final LinearLayout set_javascript_container = (LinearLayout) rootView.findViewById(R.id.set_javascript_container);

View File

@ -26,10 +26,14 @@ import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker; import android.widget.TimePicker;
import android.widget.Toast; import android.widget.Toast;
@ -49,6 +53,9 @@ public class SettingsNotificationsFragment extends Fragment {
private Context context; private Context context;
private int style; private int style;
int count = 0;
@Override @Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
@ -217,6 +224,10 @@ public class SettingsNotificationsFragment extends Fragment {
} }
}); });
final Spinner led_colour_spinner = (Spinner) rootView.findViewById(R.id.led_colour_spinner);
final TextView ledLabel = (TextView) rootView.findViewById(R.id.set_led_colour_label);
switchCompatSilent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { switchCompatSilent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@ -224,8 +235,55 @@ public class SettingsNotificationsFragment extends Fragment {
SharedPreferences.Editor editor = sharedpreferences.edit(); SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_NOTIF_SILENT, isChecked); editor.putBoolean(Helper.SET_NOTIF_SILENT, isChecked);
editor.apply(); editor.apply();
if (isChecked) {
ledLabel.setEnabled(true);
led_colour_spinner.setEnabled(true);
} else {
ledLabel.setEnabled(false);
for (View lol : led_colour_spinner.getTouchables()) {
lol.setEnabled(false);
}
}
} }
}); });
if (sharedpreferences.getBoolean(Helper.SET_NOTIF_SILENT, false)) {
ledLabel.setEnabled(true);
led_colour_spinner.setEnabled(true);
ArrayAdapter<CharSequence> adapterLEDColour = ArrayAdapter.createFromResource(getActivity(),
R.array.led_colours, android.R.layout.simple_spinner_item);
led_colour_spinner.setAdapter(adapterLEDColour);
int positionSpinnerLEDColour = (sharedpreferences.getInt(Helper.SET_LED_COLOUR, Helper.LED_COLOUR));
led_colour_spinner.setSelection(positionSpinnerLEDColour);
led_colour_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (count > 0) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putInt(Helper.SET_LED_COLOUR, position);
editor.apply();
} else {
count++;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
else {
ledLabel.setEnabled(false);
for (View lol : led_colour_spinner.getTouchables()) {
lol.setEnabled(false);
}
}
if( theme == Helper.THEME_LIGHT) { if( theme == Helper.THEME_LIGHT) {
settings_time_from.setTextColor(ContextCompat.getColor(context, R.color.white)); settings_time_from.setTextColor(ContextCompat.getColor(context, R.color.white));
settings_time_to.setTextColor(ContextCompat.getColor(context, R.color.white)); settings_time_to.setTextColor(ContextCompat.getColor(context, R.color.white));

View File

@ -43,7 +43,6 @@ public class TabLayoutSettingsFragment extends Fragment {
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.settings))); tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.settings)));
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.notifications))); tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.notifications)));
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.optimization))); tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.optimization)));
tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.profile)));
final ViewPager viewPager = (ViewPager) inflatedView.findViewById(R.id.viewpager); final ViewPager viewPager = (ViewPager) inflatedView.findViewById(R.id.viewpager);
viewPager.setAdapter(new PagerAdapter viewPager.setAdapter(new PagerAdapter
@ -90,8 +89,6 @@ public class TabLayoutSettingsFragment extends Fragment {
return new SettingsNotificationsFragment(); return new SettingsNotificationsFragment();
case 2: case 2:
return new SettingsOptimizationFragment(); return new SettingsOptimizationFragment();
case 3:
return new SettingsProfileFragment();
default: default:
return new SettingsNotificationsFragment(); return new SettingsNotificationsFragment();
} }

View File

@ -0,0 +1,64 @@
package fr.gouv.etalab.mastodon.helper;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
/**
* Created by Thomas on 03/09/2017.
* Expanded listview
*/
public class ExpandableHeightListView extends ListView
{
boolean expanded = false;
public ExpandableHeightListView(Context context)
{
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}

View File

@ -18,6 +18,8 @@ package fr.gouv.etalab.mastodon.helper;
import android.app.Activity; import android.app.Activity;
import android.app.NotificationManager;
import android.preference.PreferenceManager;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.app.DownloadManager; import android.app.DownloadManager;
@ -81,6 +83,7 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.loopj.android.http.BuildConfig; import com.loopj.android.http.BuildConfig;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
@ -92,19 +95,23 @@ import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.InetAddress; import java.net.InetAddress;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -116,6 +123,7 @@ import java.util.TimeZone;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import fr.gouv.etalab.mastodon.activities.EditProfileActivity;
import fr.gouv.etalab.mastodon.activities.HashTagActivity; import fr.gouv.etalab.mastodon.activities.HashTagActivity;
import fr.gouv.etalab.mastodon.activities.LoginActivity; import fr.gouv.etalab.mastodon.activities.LoginActivity;
import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.activities.MainActivity;
@ -126,14 +134,13 @@ import fr.gouv.etalab.mastodon.asynctasks.RemoveAccountAsyncTask;
import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Mention; import fr.gouv.etalab.mastodon.client.Entities.Mention;
import fr.gouv.etalab.mastodon.client.Entities.Notification;
import fr.gouv.etalab.mastodon.client.Entities.Status; import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite; import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import mastodon.etalab.gouv.fr.mastodon.R; import mastodon.etalab.gouv.fr.mastodon.R;
import static android.app.Notification.DEFAULT_VIBRATE;
import static android.app.Notification.FLAG_SHOW_LIGHTS;
import static android.content.Context.DOWNLOAD_SERVICE; import static android.content.Context.DOWNLOAD_SERVICE;
@ -177,10 +184,6 @@ public class Helper {
public static final String SHOW_BATTERY_SAVER_MESSAGE = "show_battery_saver_message"; public static final String SHOW_BATTERY_SAVER_MESSAGE = "show_battery_saver_message";
public static final String LAST_NOTIFICATION_MAX_ID = "last_notification_max_id"; public static final String LAST_NOTIFICATION_MAX_ID = "last_notification_max_id";
public static final String LAST_HOMETIMELINE_MAX_ID = "last_hometimeline_max_id"; public static final String LAST_HOMETIMELINE_MAX_ID = "last_hometimeline_max_id";
public static final String LAST_BUBBLE_REFRESH_NOTIF = "last_bubble_refresh_notif";
public static final String LAST_BUBBLE_REFRESH_HOME = "last_bubble_refresh_home";
public static final String LAST_MAX_ID_BUBBLE_NOTIF = "last_max_id_bubble_notif";
public static final String LAST_MAX_ID_BUBBLE_HOME = "last_max_id_bubble_home";
public static final String CLIP_BOARD = "clipboard"; public static final String CLIP_BOARD = "clipboard";
//Notifications //Notifications
public static final int NOTIFICATION_INTENT = 1; public static final int NOTIFICATION_INTENT = 1;
@ -204,8 +207,10 @@ public class Helper {
public static final String SET_ICON_SIZE = "set_icon_size"; public static final String SET_ICON_SIZE = "set_icon_size";
public static final String SET_PREVIEW_REPLIES = "set_preview_replies"; public static final String SET_PREVIEW_REPLIES = "set_preview_replies";
public static final String SET_PREVIEW_REPLIES_PP = "set_preview_replies_pp"; public static final String SET_PREVIEW_REPLIES_PP = "set_preview_replies_pp";
public static final String SET_BUBBLE_COUNTER = "set_bubble_counter";
public static final String SET_TRANSLATOR = "set_translator"; public static final String SET_TRANSLATOR = "set_translator";
public static final String SET_LED_COLOUR = "set_led_colour";
private static final String SET_TEMP_STATUS = "set_temp_status";
private static final String SET_TEMP_NOTIFICATIONS = "set_temp_notifications";
public static final int ATTACHMENT_ALWAYS = 1; public static final int ATTACHMENT_ALWAYS = 1;
public static final int ATTACHMENT_WIFI = 2; public static final int ATTACHMENT_WIFI = 2;
@ -216,6 +221,8 @@ public class Helper {
public static final int THEME_MENU = 2; public static final int THEME_MENU = 2;
public static final int THEME_MENU_TABS = 3; public static final int THEME_MENU_TABS = 3;
public static final int LED_COLOUR = 0;
public static final int TRANS_YANDEX = 0; public static final int TRANS_YANDEX = 0;
public static final int TRANS_GOOGLE = 1; public static final int TRANS_GOOGLE = 1;
public static final int TRANS_NONE = 2; public static final int TRANS_NONE = 2;
@ -226,6 +233,7 @@ public class Helper {
public static final String SET_NOTIF_MENTION = "set_notif_follow_mention"; public static final String SET_NOTIF_MENTION = "set_notif_follow_mention";
public static final String SET_NOTIF_SHARE = "set_notif_follow_share"; public static final String SET_NOTIF_SHARE = "set_notif_follow_share";
public static final String SET_NOTIF_VALIDATION = "set_share_validation"; public static final String SET_NOTIF_VALIDATION = "set_share_validation";
public static final String SET_NOTIF_VALIDATION_FAV = "set_share_validation_fav";
public static final String SET_WIFI_ONLY = "set_wifi_only"; public static final String SET_WIFI_ONLY = "set_wifi_only";
public static final String SET_NOTIF_HOMETIMELINE = "set_notif_hometimeline"; public static final String SET_NOTIF_HOMETIMELINE = "set_notif_hometimeline";
public static final String SET_NOTIF_SILENT = "set_notif_silent"; public static final String SET_NOTIF_SILENT = "set_notif_silent";
@ -235,6 +243,8 @@ public class Helper {
public static final String SET_COOKIES = "set_cookies"; public static final String SET_COOKIES = "set_cookies";
public static final String SET_FOLDER_RECORD = "set_folder_record"; public static final String SET_FOLDER_RECORD = "set_folder_record";
public static final String SET_TOOT_VISIBILITY = "set_toot_visibility"; public static final String SET_TOOT_VISIBILITY = "set_toot_visibility";
public static final String SET_DISPLAY_LOCAL = "set_display_local";
public static final String SET_DISPLAY_GLOBAL = "set_display_global";
//End points //End points
public static final String EP_AUTHORIZE = "/oauth/authorize"; public static final String EP_AUTHORIZE = "/oauth/authorize";
@ -250,7 +260,8 @@ public class Helper {
//Receiver //Receiver
public static final String SEARCH_VALIDATE_ACCOUNT = "search_validate_account"; public static final String SEARCH_VALIDATE_ACCOUNT = "search_validate_account";
public static final String HEADER_ACCOUNT = "header_account"; public static final String HEADER_ACCOUNT = "header_account";
public static final String RECEIVE_DATA = "receive_data";
public static final String RECEIVE_PICTURE = "receive_picture";
//User agent //User agent
public static final String USER_AGENT = "Mastalab/"+ BuildConfig.VERSION_NAME + " Android/"+ Build.VERSION.RELEASE; public static final String USER_AGENT = "Mastalab/"+ BuildConfig.VERSION_NAME + " Android/"+ Build.VERSION.RELEASE;
@ -258,7 +269,7 @@ public class Helper {
private static boolean menuAccountsOpened = false; private static boolean menuAccountsOpened = false;
private static final Pattern SHORTNAME_PATTERN = Pattern.compile(":([-+\\w]+):"); private static final Pattern SHORTNAME_PATTERN = Pattern.compile(":( |)([-+\\w]+):");
public static final Pattern urlPattern = Pattern.compile( public static final Pattern urlPattern = Pattern.compile(
"(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,10}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))", "(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,10}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))",
@ -273,18 +284,26 @@ public class Helper {
*/ */
public static String shortnameToUnicode(String input, boolean removeIfUnsupported) { public static String shortnameToUnicode(String input, boolean removeIfUnsupported) {
Matcher matcher = SHORTNAME_PATTERN.matcher(input); Matcher matcher = SHORTNAME_PATTERN.matcher(input);
boolean supported = Build.VERSION.SDK_INT >= 16; boolean supported = Build.VERSION.SDK_INT >= 16;
while (matcher.find()) { while (matcher.find()) {
String unicode = emoji.get(matcher.group(1)); String unicode = emoji.get(matcher.group(2));
if (unicode == null) { if (unicode == null) {
continue; continue;
} }
if (supported) { if (supported) {
input = input.replace(":" + matcher.group(1) + ":", unicode); if (matcher.group(1).equals(" "))
input = input.replace(": " + matcher.group(2) + ":", unicode);
else
input = input.replace(":" + matcher.group(2) + ":", unicode);
} else if (removeIfUnsupported) { } else if (removeIfUnsupported) {
input = input.replace(":" + matcher.group(1) + ":", ""); if (matcher.group(1).equals(" "))
input = input.replace(": " + matcher.group(2) + ":", unicode);
else
input = input.replace(":" + matcher.group(2) + ":", "");
} }
} }
return input; return input;
} }
//Emoji manager //Emoji manager
@ -596,16 +615,40 @@ public class Helper {
.setAutoCancel(true) .setAutoCancel(true)
.setContentIntent(pIntent) .setContentIntent(pIntent)
.setContentText(message); .setContentText(message);
int notifDefaults = FLAG_SHOW_LIGHTS;
notificationBuilder.setDefaults(notifDefaults);
if( sharedpreferences.getBoolean(Helper.SET_NOTIF_SILENT,false) ) { if( sharedpreferences.getBoolean(Helper.SET_NOTIF_SILENT,false) ) {
notificationBuilder.setDefaults(notifDefaults|DEFAULT_VIBRATE); notificationBuilder.setVibrate(new long[] { 500, 500, 500});
}else { }else {
String soundUri = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.getPackageName() +"/"; String soundUri = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.getPackageName() +"/";
notificationBuilder.setSound(Uri.parse(soundUri + R.raw.boop)); notificationBuilder.setSound(Uri.parse(soundUri + R.raw.boop));
} }
notificationBuilder.setLights(Color.BLUE, 500, 1000);
int ledColour = Color.BLUE;
switch (sharedpreferences.getInt(Helper.SET_LED_COLOUR, Helper.LED_COLOUR)) {
case 0: // BLUE
ledColour = Color.BLUE;
break;
case 1: // CYAN
ledColour = Color.CYAN;
break;
case 2: // MAGENTA
ledColour = Color.MAGENTA;
break;
case 3: // GREEN
ledColour = Color.GREEN;
break;
case 4: // RED
ledColour = Color.RED;
break;
case 5: // YELLOW
ledColour = Color.YELLOW;
break;
case 6: // WHITE
ledColour = Color.WHITE;
break;
}
notificationBuilder.setLights(ledColour, 500, 1000);
notificationBuilder.setContentTitle(title); notificationBuilder.setContentTitle(title);
notificationBuilder.setLargeIcon(icon); notificationBuilder.setLargeIcon(icon);
notificationManager.notify(notificationId, notificationBuilder.build()); notificationManager.notify(notificationId, notificationBuilder.build());
@ -964,6 +1007,8 @@ public class Helper {
TextView ownerStatus = (TextView) headerLayout.findViewById(R.id.owner_status); TextView ownerStatus = (TextView) headerLayout.findViewById(R.id.owner_status);
TextView ownerFollowing = (TextView) headerLayout.findViewById(R.id.owner_following); TextView ownerFollowing = (TextView) headerLayout.findViewById(R.id.owner_following);
TextView ownerFollowers = (TextView) headerLayout.findViewById(R.id.owner_followers); TextView ownerFollowers = (TextView) headerLayout.findViewById(R.id.owner_followers);
ImageView header_edit_profile = (ImageView) headerLayout.findViewById(R.id.header_edit_profile);
header_edit_profile.setOnClickListener(null);
if( account == null ) { if( account == null ) {
Helper.logout(activity); Helper.logout(activity);
Intent myIntent = new Intent(activity, LoginActivity.class); Intent myIntent = new Intent(activity, LoginActivity.class);
@ -1013,6 +1058,13 @@ public class Helper {
} }
}); });
} }
header_edit_profile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(activity, EditProfileActivity.class);
activity.startActivity(intent);
}
});
} }
profilePicture.setOnClickListener(null); profilePicture.setOnClickListener(null);
profilePicture.setOnClickListener(new View.OnClickListener() { profilePicture.setOnClickListener(new View.OnClickListener() {
@ -1544,4 +1596,124 @@ public class Helper {
} }
} }
} }
public static int getUnreadNotifications(Context context, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
Gson gson = new Gson();
String json = sharedpreferences.getString(Helper.SET_TEMP_NOTIFICATIONS + userId, null);
Type type = new TypeToken<ArrayList<Notification>>() {}.getType();
ArrayList<Notification> notifications = gson.fromJson(json, type);
return (notifications == null)?0:notifications.size();
}
public static int getUnreadToots(Context context, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
Gson gson = new Gson();
String json = sharedpreferences.getString(Helper.SET_TEMP_STATUS + userId, null);
Type type = new TypeToken<ArrayList<Status>>() {}.getType();
ArrayList<Status> statuses = gson.fromJson(json, type);
return (statuses == null)?0:statuses.size();
}
public static void cacheStatus(Context context, Status status, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SharedPreferences.Editor editor = sharedpreferences.edit();
ArrayList<Status> statuses = getTempStatus(context, userId);
if( statuses == null)
statuses = new ArrayList<>();
if( status != null)
statuses.add(0,status);
Gson gson = new Gson();
String serializedAccounts = gson.toJson(statuses);
editor.putString(Helper.SET_TEMP_STATUS + userId, serializedAccounts);
editor.apply();
}
public static void cacheStatusClear(Context context, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SharedPreferences.Editor editor = sharedpreferences.edit();
ArrayList<Status> statuses = new ArrayList<>();
Gson gson = new Gson();
String serializedAccounts = gson.toJson(statuses);
editor.putString(Helper.SET_TEMP_STATUS + userId, serializedAccounts);
editor.apply();
//noinspection EmptyTryBlock
try {
NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
long notif_id = Long.parseLong(userId);
int notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2);
notificationManager.cancel(notificationId);
}catch (Exception ignored){}
}
public static ArrayList<Status> getTempStatus(Context context, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
Gson gson = new Gson();
String json = sharedpreferences.getString(Helper.SET_TEMP_STATUS + userId, null);
Type type = new TypeToken<ArrayList<Status>>() {}.getType();
return gson.fromJson(json, type);
}
public static void cacheNotifications(Context context, Notification notification, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SharedPreferences.Editor editor = sharedpreferences.edit();
ArrayList<Notification> notifications = getTempNotification(context, userId);
if( notifications == null)
notifications = new ArrayList<>();
if( notification != null)
notifications.add(0,notification);
Gson gson = new Gson();
String serializedAccounts = gson.toJson(notifications);
editor.putString(Helper.SET_TEMP_NOTIFICATIONS + userId, serializedAccounts);
editor.apply();
}
public static void cacheNotificationsClear(Context context, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SharedPreferences.Editor editor = sharedpreferences.edit();
ArrayList<Notification> notifications = new ArrayList<>();
Gson gson = new Gson();
String serializedAccounts = gson.toJson(notifications);
editor.putString(Helper.SET_TEMP_NOTIFICATIONS + userId, serializedAccounts);
editor.apply();
//noinspection EmptyTryBlock
try {
NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
long notif_id = Long.parseLong(userId);
int notificationId = ((notif_id + 1) > 2147483647) ? (int) (2147483647 - notif_id - 1) : (int) (notif_id + 1);
notificationManager.cancel(notificationId);
}catch (Exception ignored){}
}
public static ArrayList<Notification> getTempNotification(Context context, String userId){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( userId == null)
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
Gson gson = new Gson();
String json = sharedpreferences.getString(Helper.SET_TEMP_NOTIFICATIONS + userId, null);
Type type = new TypeToken<ArrayList<Notification>>() {}.getType();
return gson.fromJson(json, type);
}
} }

View File

@ -0,0 +1,9 @@
package fr.gouv.etalab.mastodon.helper;
/**
* Created by Thomas on 02/09/2017.
*/
public class ManageHeader {
}

View File

@ -0,0 +1,24 @@
/* Copyright 2017 Thomas Schneider
*
* This file is a part of Mastalab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.interfaces;
/**
* Created by Thomas on 02/09/2017.
* Interface for retrieving meta data
*/
public interface OnRetrieveMetaDataInterface {
void onRetrieveMetaData(boolean error, String image, String title, String description);
}

View File

@ -20,5 +20,5 @@ package fr.gouv.etalab.mastodon.interfaces;
* Interface for retrieving a remote account * Interface for retrieving a remote account
*/ */
public interface OnRetrieveRemoteAccountInterface { public interface OnRetrieveRemoteAccountInterface {
void onRetrieveRemoteAccount(boolean error, String name, String username, boolean locked, String avatar, String bio, int statusCount, int followingCount, int followersCount); void onRetrieveRemoteAccount(boolean error, String name, String username, String instance, boolean locked, String avatar, String bio, String statusCount, String followingCount, String followersCount);
} }

View File

@ -0,0 +1,28 @@
/* 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 java.util.ArrayList;
import fr.gouv.etalab.mastodon.client.Entities.Account;
/**
* Created by Thomas on 03/09/2017.
* Interface for search dev accounts
*/
public interface OnRetrieveSearchDevelopersAccountshInterface {
void onRetrieveSearchDevelopersAccounts(ArrayList<Account> accounts);
}

View File

@ -127,24 +127,17 @@ public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineSe
@Override @Override
public void onRetrieveHomeTimelineService(APIResponse apiResponse, String acct, String userId) { public void onRetrieveHomeTimelineService(APIResponse apiResponse, String acct, final String userId) {
List<Status> statuses = apiResponse.getStatuses(); final List<Status> statuses = apiResponse.getStatuses();
if( apiResponse.getError() != null || statuses == null || statuses.size() == 0) if( apiResponse.getError() != null || statuses == null || statuses.size() == 0)
return; return;
final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
final String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null); final String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null);
if( max_id == null){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, apiResponse.getSince_id());
editor.apply();
return;
}
//No previous notifications in cache, so no notification will be sent //No previous notifications in cache, so no notification will be sent
String message; String message;
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, apiResponse.getSince_id());
editor.apply();
for(Status status: statuses){ for(Status status: statuses){
//The notification associated to max_id is discarded as it is supposed to have already been sent //The notification associated to max_id is discarded as it is supposed to have already been sent
//Also, if the toot comes from the owner, we will avoid to warn him/her... //Also, if the toot comes from the owner, we will avoid to warn him/her...
@ -189,11 +182,17 @@ public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineSe
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage); super.onLoadingComplete(imageUri, view, loadedImage);
notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, finalMessage); notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, finalMessage);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, statuses.get(0).getId());
editor.apply();
} }
@Override @Override
public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){ public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(), notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.mastodonlogo), finalTitle, finalMessage); R.drawable.mastodonlogo), finalTitle, finalMessage);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, statuses.get(0).getId());
editor.apply();
}}); }});
} }
@ -201,4 +200,4 @@ public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineSe
} }
} }

View File

@ -133,8 +133,8 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
@Override @Override
public void onRetrieveNotifications(APIResponse apiResponse, String acct, String userId, boolean refreshData) { public void onRetrieveNotifications(APIResponse apiResponse, String acct, final String userId, boolean refreshData) {
List<Notification> notifications = apiResponse.getNotifications(); final List<Notification> notifications = apiResponse.getNotifications();
if( apiResponse.getError() != null || notifications == null || notifications.size() == 0) if( apiResponse.getError() != null || notifications == null || notifications.size() == 0)
return; return;
Bitmap icon_notification = null; Bitmap icon_notification = null;
@ -144,12 +144,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true);
boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true);
final String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId, null); final String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId, null);
if( max_id == null){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, apiResponse.getSince_id());
editor.apply();
return;
}
//No previous notifications in cache, so no notification will be sent //No previous notifications in cache, so no notification will be sent
int newFollows = 0; int newFollows = 0;
@ -176,7 +171,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
title = String.format("@%s %s", notification.getAccount().getUsername(),getContext().getString(R.string.notif_mention)); title = String.format("@%s %s", notification.getAccount().getUsername(),getContext().getString(R.string.notif_mention));
} }
} }
break; break;
case "reblog": case "reblog":
if(notif_share){ if(notif_share){
newShare++; newShare++;
@ -217,9 +212,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
default: default:
} }
} }
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, apiResponse.getSince_id());
editor.apply();
int allNotifCount = newFollows + newAdds + newAsks + newMentions + newShare; int allNotifCount = newFollows + newAdds + newAsks + newMentions + newShare;
if( allNotifCount > 0){ if( allNotifCount > 0){
//Some others notification //Some others notification
@ -254,18 +247,26 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
@Override @Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage); super.onLoadingComplete(imageUri, view, loadedImage);
if( max_id != null) if( max_id != null) {
notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, message); notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, message);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, notifications.get(0).getId());
editor.apply();
}
} }
@Override @Override
public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){ public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
if( max_id != null) if( max_id != null) {
notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(), notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.mastodonlogo), finalTitle, message); R.drawable.mastodonlogo), finalTitle, message);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, notifications.get(0).getId());
editor.apply();
}
}}); }});
} }
} }
} }
} }

View File

@ -17,7 +17,6 @@ package fr.gouv.etalab.mastodon.jobs;
import android.content.Context; import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import com.evernote.android.job.Job; import com.evernote.android.job.Job;
import com.evernote.android.job.JobRequest; import com.evernote.android.job.JobRequest;

View File

@ -0,0 +1,38 @@
package fr.gouv.etalab.mastodon.services;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import java.util.List;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
/**
* Created by Thomas on 29/08/2017.
* BroadcastReceiver to start service when device boot
*/
public class BootService extends BroadcastReceiver {
public BootService() {
}
@Override
public void onReceive(Context context, Intent intent) {
SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
List<Account> accounts = new AccountDAO(context, db).getAllAccount();
if( accounts != null){
for (Account account: accounts) {
Intent intentService = new Intent(context, StreamingService.class);
intentService.putExtra("acccountId", account.getId());
intentService.putExtra("accountAcct", account.getAcct());
context.startService(intentService);
}
}
}
}

View File

@ -0,0 +1,503 @@
package fr.gouv.etalab.mastodon.services;
/* 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.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import android.os.StrictMode;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.text.Html;
import android.util.Log;
import android.view.View;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import fr.gouv.etalab.mastodon.activities.MainActivity;
import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Notification;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.client.TLSSocketFactory;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import mastodon.etalab.gouv.fr.mastodon.R;
import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT;
import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION;
import static fr.gouv.etalab.mastodon.helper.Helper.NOTIFICATION_INTENT;
import static fr.gouv.etalab.mastodon.helper.Helper.PREF_KEY_ID;
import static fr.gouv.etalab.mastodon.helper.Helper.canNotify;
import static fr.gouv.etalab.mastodon.helper.Helper.notify_user;
/**
* Created by Thomas on 28/08/2017.
* Manage service for streaming api and new notifications
*/
public class StreamingService extends Service {
private String message;
private int notificationId;
private Intent intent;
private String lastPreviousContent;
private static HashMap<String, HttpsURLConnection> connectionHashMap = new HashMap<>();
private static HashMap<String, Boolean> isConnectingHashMap = new HashMap<>();
private EventStreaming lastEvent;
public enum EventStreaming{
UPDATE,
NOTIFICATION,
DELETE,
NONE
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if( intent != null){
String accountId = intent.getStringExtra("accountId");
String accountAcct = intent.getStringExtra("accountAcct");
if( accountId != null && accountAcct != null){
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account account = new AccountDAO(getApplicationContext(), db).getAccountByIDAcct(accountId, accountAcct);
if( account != null)
callAsynchronousTask(account);
}else {
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
List<Account> accounts = new AccountDAO(getApplicationContext(), db).getAllAccount();
if( accounts != null){
for (Account account: accounts) {
intent = new Intent(getApplicationContext(), StreamingService.class);
intent.putExtra("accountId", account.getId());
intent.putExtra("accountAcct", account.getAcct());
startService(intent);
}
}
}
}
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* Task in background starts here.
*/
private void callAsynchronousTask(final Account account) {
//If an Internet connection and user agrees with notification refresh
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
//Check which notifications the user wants to see
boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true);
boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true);
boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true);
boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true);
boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true);
//User disagree with all notifications
if( !notif_follow && !notif_add && !notif_ask && !notif_mention && !notif_share)
return; //Nothing is done
//No account connected, the service is stopped
if(!Helper.isLoggedIn(getApplicationContext()))
return;
//If WIFI only and on WIFI OR user defined any connections to use the service.
if( isConnectingHashMap.get(account.getAcct()+account.getId()) != null && isConnectingHashMap.get(account.getAcct()+account.getId()))
return;
if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getApplicationContext())) {
Thread readThread = new Thread(new Runnable() {
@Override
public void run() {
try {
boolean connectionAlive = false;
isConnectingHashMap.put(account.getAcct()+account.getId(), true);
if( connectionHashMap.get(account.getAcct()+account.getId()) != null) {
try {
connectionAlive = (connectionHashMap.get(account.getAcct()+account.getId()).getResponseCode() == 200);
} catch (Exception e) {
connectionAlive = false;
}
}
if( connectionAlive) {
HttpsURLConnection httpsURLConnection = connectionHashMap.get(account.getAcct() + account.getId());
if( httpsURLConnection != null)
httpsURLConnection.disconnect();
}
try {
URL url = new URL("https://" + account.getInstance() + "/api/v1/streaming/user");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Authorization", "Bearer " + account.getToken());
urlConnection.setRequestProperty("Connection", "Keep-Alive");
urlConnection.setRequestProperty("Keep-Alive", "header");
urlConnection.setRequestProperty("Connection", "close");
urlConnection.setSSLSocketFactory(new TLSSocketFactory());
connectionHashMap.put(account.getAcct()+account.getId(), urlConnection);
InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());
readStream(inputStream, account);
} catch (IOException | NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
forceRestart(account);
}
} catch (Exception ignored) {
}
}
});
readThread.start();
}
}
@SuppressWarnings("ConstantConditions")
private String readStream(InputStream inputStream, final Account account) {
BufferedReader reader = null;
try{
reader = new BufferedReader(new InputStreamReader(inputStream));
String event;
EventStreaming eventStreaming = null;
//noinspection InfiniteLoopStatement
while(true){
try {
event = reader.readLine();
}catch (Exception e){
e.printStackTrace();
forceRestart(account);
break;
}
if (event !=null){
if( (lastEvent == EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) {
switch (event.trim()) {
case "event: update":
lastEvent = EventStreaming.UPDATE;
break;
case "event: notification":
lastEvent = EventStreaming.NOTIFICATION;
break;
case "event: delete":
lastEvent = EventStreaming.DELETE;
break;
default:
lastEvent = EventStreaming.NONE;
}
}else{
if( !event.startsWith("data: ")){
lastEvent = EventStreaming.NONE;
continue;
}
event = event.substring(6);
if(lastEvent == EventStreaming.UPDATE) {
eventStreaming = EventStreaming.UPDATE;
}else if(lastEvent == EventStreaming.NOTIFICATION) {
eventStreaming = EventStreaming.NOTIFICATION;
}else if( lastEvent == EventStreaming.DELETE) {
eventStreaming = EventStreaming.DELETE;
event = "{id:" + event + "}";
}else {
eventStreaming = EventStreaming.UPDATE;
}
lastEvent = EventStreaming.NONE;
try {
JSONObject eventJson = new JSONObject(event);
onRetrieveStreaming(eventStreaming, eventJson, account.getAcct(), account.getId());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(reader != null){
try{
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
forceRestart(account);
}
return null;
}
private void forceRestart(Account account){
isConnectingHashMap.put(account.getAcct()+account.getId(), false);
SystemClock.sleep(1000);
Intent intent = new Intent(getApplicationContext(), StreamingService.class);
intent.putExtra("accountId", account.getId());
intent.putExtra("accountAcct", account.getAcct());
startService(intent);
}
@Override
public void onTaskRemoved(Intent rootIntent) {
Intent intent = new Intent(getApplicationContext(), StreamingService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
super.onTaskRemoved(rootIntent);
}
public void onRetrieveStreaming(EventStreaming event, JSONObject response, String acct, String userId) {
if( response == null )
return;
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true);
boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true);
boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true);
boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true);
//No previous notifications in cache, so no notification will be sent
boolean notify = false;
String notificationUrl = null;
String title = null;
Status status = null;
Notification notification = null;
String dataId = null;
if( event == EventStreaming.NOTIFICATION){
notification = API.parseNotificationResponse(getApplicationContext(), response);
switch (notification.getType()){
case "mention":
if(notif_mention){
lastPreviousContent = notification.getStatus().getContent();
notify = true;
notificationUrl = notification.getAccount().getAvatar();
if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 )
title = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_mention));
else
title = String.format("%s %s", notification.getAccount().getUsername(),getString(R.string.notif_mention));
}
break;
case "reblog":
if(notif_share){
notify = true;
notificationUrl = notification.getAccount().getAvatar();
if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 )
title = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_reblog));
else
title = String.format("%s %s", notification.getAccount().getUsername(),getString(R.string.notif_reblog));
}
break;
case "favourite":
if(notif_add){
notify = true;
notificationUrl = notification.getAccount().getAvatar();
if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 )
title = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_favourite));
else
title = String.format("%s %s", notification.getAccount().getUsername(),getString(R.string.notif_favourite));
}
break;
case "follow":
if(notif_follow){
notify = true;
notificationUrl = notification.getAccount().getAvatar();
if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 )
title = String.format("%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_follow));
else
title = String.format("%s %s", notification.getAccount().getUsername(),getString(R.string.notif_follow));
}
break;
default:
break;
}
Helper.cacheNotifications(getApplicationContext(), notification, userId);
if( notification.getStatus().getContent()!= null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
message = Html.fromHtml(notification.getStatus().getContent(), Html.FROM_HTML_MODE_LEGACY).toString();
else
//noinspection deprecation
message = Html.fromHtml(notification.getStatus().getContent()).toString();
message = message.substring(0, message.length()>49?49:message.length());
message = message + "";
}else{
message = "";
}
}else if ( event == EventStreaming.UPDATE){
status = API.parseStatuses(getApplicationContext(), response);
status.setReplies(new ArrayList<Status>()); //Force to don't display replies
status.setNew(true);
Helper.cacheStatus(getApplicationContext(), status, userId);
if( status.getContent() != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
message = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString();
else
//noinspection deprecation
message = Html.fromHtml(status.getContent()).toString();
message = message.substring(0, message.length()>49?49:message.length());
message = message + "";
}else{
message = "";
}
title = getString(R.string.notif_pouet, status.getAccount().getUsername());
notificationUrl = status.getAccount().getAvatar();
}else if( event == EventStreaming.DELETE){
try {
dataId = response.getString("id");
} catch (JSONException e) {
e.printStackTrace();
}
}
//Check which user is connected and if activity is to front
boolean activityVisible = false;
try{
activityVisible = MainActivity.isActivityVisible();
}catch (Exception ignored){}
String connectedUser = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(connectedUser);
//User receiving the notification is connected
if( isCurrentAccountLoggedIn(acct, userId)){
notify = false;
Intent intentBC = new Intent(Helper.RECEIVE_DATA);
intentBC.putExtra("eventStreaming", event);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentBC);
}
//User receiving the notification is connected and application is to front, notification won't be pushed
//Instead, the interaction is done in the activity
if( activityVisible && isCurrentAccountLoggedIn(acct, userId)){
notify = false;
}else if(event == EventStreaming.NOTIFICATION ){
notify = true;
}else if(event == EventStreaming.UPDATE ){
//lastPreviousContent contains the content of the last notification, if it was a mention it will avoid to push two notifications
if( account == null || (lastPreviousContent != null && lastPreviousContent.equals(status.getContent()))) {
notify = false;
}else {
notify = true;
//Retrieve users in db that owner has, and if the toot matches one of them we don't notify
List<Account> accounts = new AccountDAO(getApplicationContext(),db).getAllAccount();
for(Account act_tmp: accounts) {
if(notify && act_tmp.getAcct().trim().equals(status.getAccount().getAcct()) && act_tmp.getId().trim().equals(status.getAccount().getId().trim())){
notify = false;
}
}
//Here we check if the user wants home timeline notifications
if( notify )
notify = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true);
}
lastPreviousContent = status.getContent();
}
//All is good here for a notification, we will know check if it can be done depending of the hour
if( notify)
notify = canNotify(getApplicationContext());
if( notify && event == EventStreaming.NOTIFICATION){
intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );
intent.putExtra(INTENT_ACTION, NOTIFICATION_INTENT);
intent.putExtra(PREF_KEY_ID, userId);
long notif_id = Long.parseLong(userId);
notificationId = ((notif_id + 1) > 2147483647) ? (int) (2147483647 - notif_id - 1) : (int) (notif_id + 1);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, notification.getId());
editor.apply();
}
if( notify && event == EventStreaming.UPDATE) {
intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(INTENT_ACTION, HOME_TIMELINE_INTENT);
intent.putExtra(PREF_KEY_ID, userId);
long notif_id = Long.parseLong(userId);
notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, status.getId());
editor.apply();
}
if( notify){
if( notificationUrl != null){
ImageLoader imageLoaderNoty = ImageLoader.getInstance();
File cacheDir = new File(getApplicationContext().getCacheDir(), getString(R.string.app_name));
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.imageDownloader(new PatchBaseImageDownloader(getApplicationContext()))
.threadPoolSize(5)
.threadPriority(Thread.MIN_PRIORITY + 3)
.denyCacheImageMultipleSizesInMemory()
.diskCache(new UnlimitedDiskCache(cacheDir))
.build();
imageLoaderNoty.init(config);
DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
final String finalTitle = title;
imageLoaderNoty.loadImage(notificationUrl, options, new SimpleImageLoadingListener(){
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
notify_user(getApplicationContext(), intent, notificationId, loadedImage, finalTitle, message);
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason){
notify_user(getApplicationContext(), intent, notificationId, BitmapFactory.decodeResource(getApplicationContext().getResources(),
R.drawable.mastodonlogo), finalTitle, message);
}});
}
}
}
private boolean isCurrentAccountLoggedIn(String acct, String userId){
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userconnected = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(userconnected);
return acct.trim().equals(account.getAcct().trim()) && userId.trim().equals(account.getId().trim());
}
}

View File

@ -133,6 +133,21 @@ public class AccountDAO {
} }
} }
/**
* Returns an Account by its id and acct
* @param accountId String
* @param accountAcct String
* @return Account
*/
public Account getAccountByIDAcct(String accountId, String accountAcct){
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, Sqlite.COL_USER_ID + " = '" + accountId + "' AND " + Sqlite.COL_ACCT + " = '" + accountAcct + "'", null, null, null, null, "1");
return cursorToUser(c);
} catch (Exception e) {
return null;
}
}
/** /**
* Returns an Account by id and instance * Returns an Account by id and instance
* @param accountId String * @param accountId String

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1008 B

After

Width:  |  Height:  |  Size: 1008 B

View File

@ -16,9 +16,9 @@
see <http://www.gnu.org/licenses>. see <http://www.gnu.org/licenses>.
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
> >
<!-- About app name --> <!-- About app name -->
<TextView <TextView
@ -40,40 +40,49 @@
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<!-- About developer --> <!-- About developer -->
<LinearLayout <TextView
android:orientation="horizontal" android:layout_width="wrap_content"
android:padding="20dp" android:layout_height="wrap_content"
android:gravity="center" android:layout_gravity="center_vertical|center_horizontal"
android:layout_marginTop="10dp"
android:clickable="true"
android:gravity="center_vertical"
android:padding="5dp"
android:text="@string/about_developer"
android:textColor="@color/mastodonC4"
android:textSize="16sp"/>
<fr.gouv.etalab.mastodon.helper.ExpandableHeightListView
android:id="@+id/lv_developers"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
<TextView android:layout_gravity="center_vertical|center_horizontal"
android:textSize="18sp" android:layout_marginLeft="150dp"
android:layout_gravity="center" android:layout_marginRight="150dp"
android:gravity="center" android:divider="@null"
android:clickable="true" android:scrollbars="none"/>
android:layout_width="200dp"
android:text="@string/about_developer" <TextView
android:layout_height="wrap_content" /> android:id="@+id/about_thanks_dev"
<Button android:layout_width="wrap_content"
android:id="@+id/about_developer" android:layout_height="wrap_content"
android:text="@string/about_developer_action" android:layout_gravity="center_vertical|center_horizontal"
android:layout_width="150dp" android:layout_marginTop="10dp"
style="@style/Base.Widget.AppCompat.Button.Colored" android:gravity="center_vertical"
android:layout_height="wrap_content" /> android:padding="5dp"
</LinearLayout> android:text="@string/thanks_text_dev"
<LinearLayout android:textColor="@color/mastodonC4"
android:orientation="horizontal" android:textSize="16sp"/>
android:padding="10dp"
<fr.gouv.etalab.mastodon.helper.ExpandableHeightListView
android:id="@+id/lv_contributors"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
<TextView android:layout_gravity="center_vertical|center_horizontal"
android:id="@+id/about_thanks_dev" android:layout_marginLeft="150dp"
android:text="@string/thanks_text_dev" android:layout_marginRight="150dp"
android:layout_marginTop="20dp" android:divider="@null"
android:gravity="center_horizontal" android:scrollbars="none"/>
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- About license --> <!-- About license -->
<LinearLayout <LinearLayout
@ -89,12 +98,13 @@
android:gravity="center" android:gravity="center"
android:layout_width="200dp" android:layout_width="200dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<Button <Button
android:id="@+id/about_license" android:id="@+id/about_license"
android:text="@string/about_license_action"
style="@style/Base.Widget.AppCompat.Button.Colored" style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="150dp" android:layout_width="165dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:text="@string/about_license_action"/>
</LinearLayout> </LinearLayout>
<!-- About license --> <!-- About license -->
@ -111,12 +121,13 @@
android:gravity="center" android:gravity="center"
android:layout_width="200dp" android:layout_width="200dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<Button <Button
android:id="@+id/about_code" android:id="@+id/about_code"
android:text="@string/about_code_action"
style="@style/Base.Widget.AppCompat.Button.Colored" style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="150dp" android:layout_width="165dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:text="@string/about_code_action"/>
</LinearLayout> </LinearLayout>
@ -136,12 +147,13 @@
android:layout_width="200dp" android:layout_width="200dp"
android:text="@string/about_thekinrar" android:text="@string/about_thekinrar"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<Button <Button
android:id="@+id/about_thekinrar" android:id="@+id/about_thekinrar"
android:text="@string/about_thekinrar_action"
android:layout_width="150dp"
style="@style/Base.Widget.AppCompat.Button.Colored" style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_height="wrap_content" /> android:layout_width="165dp"
android:layout_height="wrap_content"
android:text="@string/about_thekinrar_action"/>
</LinearLayout> </LinearLayout>
<!-- About translation --> <!-- About translation -->
@ -158,12 +170,13 @@
android:gravity="center" android:gravity="center"
android:layout_width="200dp" android:layout_width="200dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<Button <Button
android:id="@+id/about_translation" android:id="@+id/about_translation"
android:text="@string/about_yandex_action"
style="@style/Base.Widget.AppCompat.Button.Colored" style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="150dp" android:layout_width="165dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:text="@string/about_yandex_action"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"

View File

@ -68,16 +68,32 @@
android:maxLines="1" android:maxLines="1"
android:textSize="16sp" android:textSize="16sp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView <LinearLayout
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:textColor="?attr/color_in_account_header"
android:id="@+id/account_un"
android:maxLines="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
/> android:orientation="horizontal">
<TextView
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:textColor="?attr/color_in_account_header"
android:id="@+id/account_un"
android:maxLines="1"
android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_height="wrap_content"
/>
<ImageView
android:visibility="gone"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:gravity="center_horizontal|bottom"
android:src="@drawable/ic_action_edit"
android:id="@+id/header_edit_profile"
android:layout_width="20dp"
android:layout_height="20dp"
tools:ignore="ContentDescription" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -40,6 +40,12 @@
android:text="@string/set_share_validation" android:text="@string/set_share_validation"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_share_validation_fav"
android:layout_width="wrap_content"
android:text="@string/set_share_validation_fav"
android:layout_height="wrap_content" />
<CheckBox <CheckBox
android:id="@+id/set_show_error_messages" android:id="@+id/set_show_error_messages"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -58,11 +64,6 @@
android:text="@string/set_auto_store_toot" android:text="@string/set_auto_store_toot"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_bubble_counter"
android:layout_width="wrap_content"
android:text="@string/set_bubble_counter"
android:layout_height="wrap_content" />
<CheckBox <CheckBox
android:id="@+id/set_preview_reply" android:id="@+id/set_preview_reply"
@ -70,6 +71,17 @@
android:text="@string/set_preview_reply" android:text="@string/set_preview_reply"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_display_local"
android:layout_width="wrap_content"
android:text="@string/set_display_local"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_display_global"
android:layout_width="wrap_content"
android:text="@string/set_display_global"
android:layout_height="wrap_content" />
<LinearLayout <LinearLayout
android:id="@+id/set_preview_reply_pp_container" android:id="@+id/set_preview_reply_pp_container"
@ -94,6 +106,24 @@
/> />
</LinearLayout> </LinearLayout>
<!-- TABS Layout -->
<LinearLayout
android:id="@+id/translation_layout_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/about_yandex"/>
<Spinner
android:id="@+id/translation_layout_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -138,25 +168,7 @@
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<!-- TABS Layout -->
<LinearLayout
android:id="@+id/translation_layout_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/about_yandex"/>
<Spinner
android:id="@+id/translation_layout_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/set_javascript_container" android:id="@+id/set_javascript_container"

View File

@ -15,172 +15,188 @@
You should have received a copy of the GNU General Public License along with Mastalab; if not, You should have received a copy of the GNU General Public License along with Mastalab; if not,
see <http://www.gnu.org/licenses>. see <http://www.gnu.org/licenses>.
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
> >
<!-- About app name --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<TextView
android:layout_marginTop="20dp"
android:textSize="20sp"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:text="@string/app_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
<!-- About version --> android:orientation="vertical"
<TextView >
android:layout_marginTop="10dp" <!-- About app name -->
android:id="@+id/about_version"
android:textSize="16sp"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- About developer -->
<LinearLayout
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView <TextView
android:layout_marginTop="10dp"
android:textSize="20sp"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:text="@string/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- About version -->
<TextView
android:layout_marginTop="10dp"
android:id="@+id/about_version"
android:textSize="16sp" android:textSize="16sp"
android:layout_gravity="center" android:layout_gravity="center_horizontal"
android:gravity="center" android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- About developer -->
<TextView
android:padding="5dp"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="true" android:clickable="true"
android:layout_weight="2" android:textColor="@color/mastodonC4"
android:layout_width="0dp" android:gravity="center_vertical"
android:text="@string/about_developer" android:text="@string/about_developer"
android:layout_height="wrap_content" /> android:textSize="16sp"/>
<Button <fr.gouv.etalab.mastodon.helper.ExpandableHeightListView
android:id="@+id/about_developer" android:id="@+id/lv_developers"
android:text="@string/about_developer_action" android:layout_width="match_parent"
android:layout_weight="3" android:layout_height="wrap_content"
android:layout_width="0dp" android:scrollbars="none"
style="@style/Base.Widget.AppCompat.Button.Colored" android:divider="@null"/>
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView <TextView
android:padding="5dp"
android:layout_marginTop="10dp"
android:id="@+id/about_thanks_dev" android:id="@+id/about_thanks_dev"
android:text="@string/thanks_text_dev"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:textColor="@color/mastodonC4"
</LinearLayout> android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
<!-- About license --> android:gravity="center_vertical"
<LinearLayout
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="@string/about_license"
android:textSize="16sp" android:textSize="16sp"
android:layout_gravity="center" android:text="@string/thanks_text_dev"/>
android:gravity="center"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/about_license"
android:text="@string/about_license_action"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- About license --> <fr.gouv.etalab.mastodon.helper.ExpandableHeightListView
<LinearLayout android:id="@+id/lv_contributors"
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="@string/about_code"
android:textSize="16sp"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/about_code"
android:text="@string/about_code_action"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- About The Kinrar's API -->
<LinearLayout
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textSize="16sp"
android:layout_gravity="center"
android:gravity="center"
android:clickable="true"
android:layout_weight="2"
android:layout_width="0dp"
android:text="@string/about_thekinrar"
android:layout_height="wrap_content" />
<Button
android:id="@+id/about_thekinrar"
android:text="@string/about_thekinrar_action"
android:layout_weight="3"
android:layout_width="0dp"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- About translation -->
<LinearLayout
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="@string/about_yandex"
android:textSize="16sp"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/about_translation"
android:text="@string/about_yandex_action"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="@string/thanks_text"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:scrollbars="none"
android:divider="@null"/>
<!-- About license -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:gravity="center"
android:text="@string/about_license"
android:textSize="16sp"/>
<Button
android:id="@+id/about_license"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@string/about_license_action"/>
</LinearLayout>
<!-- About license -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:gravity="center"
android:text="@string/about_code"
android:textSize="16sp"/>
<Button
android:id="@+id/about_code"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@string/about_code_action"/>
</LinearLayout>
<!-- About The Kinrar's API -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:clickable="true"
android:gravity="center"
android:text="@string/about_thekinrar"
android:textSize="16sp"/>
<Button
android:id="@+id/about_thekinrar"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@string/about_thekinrar_action"/>
</LinearLayout>
<!-- About translation -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:gravity="center"
android:text="@string/about_yandex"
android:textSize="16sp"/>
<Button
android:id="@+id/about_translation"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@string/about_yandex_action"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/thanks_text"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </ScrollView>

View File

@ -68,16 +68,32 @@
android:maxLines="1" android:maxLines="1"
android:textSize="16sp" android:textSize="16sp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView <LinearLayout
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:textColor="?attr/color_in_account_header"
android:id="@+id/account_un"
android:maxLines="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
/> android:orientation="horizontal">
<TextView
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:textColor="?attr/color_in_account_header"
android:id="@+id/account_un"
android:maxLines="1"
android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_height="wrap_content"
/>
<ImageView
android:visibility="gone"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:gravity="center_horizontal|bottom"
android:src="@drawable/ic_action_edit"
android:id="@+id/header_edit_profile"
android:layout_width="20dp"
android:layout_height="20dp"
tools:ignore="ContentDescription" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -0,0 +1,78 @@
<?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>.
-->
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/tools"
style="?attr/cardStyle"
android:layout_marginTop="10dp"
card_view:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true">
<LinearLayout
android:id="@+id/acccount_container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_gravity="center_horizontal"
android:id="@+id/account_pp"
android:layout_margin="10dp"
android:layout_width="60dp"
android:layout_height="60dp"
tools:ignore="ContentDescription" />
<LinearLayout
android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/account_dn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/account_un"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:layout_gravity="center"
app:fabSize="mini"
android:id="@+id/account_follow"
android:textAllCaps="false"
android:src="@drawable/ic_user_plus"
android:gravity="center"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:layout_width="40dp"
android:layout_height="40dp"
/>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@ -35,7 +35,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/main_container" android:id="@+id/main_container"
android:orientation="horizontal"> android:orientation="horizontal"
card_view:ignore="DisableBaselineAlignment">
<LinearLayout <LinearLayout
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -71,21 +71,15 @@
style="?attr/shapeBorder" style="?attr/shapeBorder"
android:visibility="gone" android:visibility="gone"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<Button
android:id="@+id/status_translate" <ImageView
android:layout_width="50dp" android:layout_centerHorizontal="true"
android:layout_height="wrap_content"
android:layout_marginTop="70dp" android:layout_marginTop="70dp"
android:layout_marginLeft="5dp" android:id="@+id/new_element"
android:layout_marginStart="5dp" android:visibility="gone"
android:layout_alignParentStart="true" android:src="@drawable/ic_fiber_new"
android:layout_alignParentLeft="true" android:layout_width="wrap_content"
android:scaleType="center" android:layout_height="wrap_content"
android:drawablePadding="0dp"
android:paddingStart="17dp"
android:paddingLeft="17dp"
android:drawableStart="@drawable/ic_translate"
android:drawableLeft="@drawable/ic_translate"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
</RelativeLayout> </RelativeLayout>
<LinearLayout <LinearLayout
@ -196,6 +190,14 @@
android:text="Powered by Yandex.Translate" android:text="Powered by Yandex.Translate"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
<TextView
android:id="@+id/google_translate"
android:layout_width="match_parent"
android:padding="2dp"
android:gravity="end"
android:text="Powered by Google Translate"
android:layout_height="wrap_content"
tools:ignore="HardcodedText" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -330,11 +332,22 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<TextView
android:visibility="gone"
android:text="@string/translate_toot"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical|end"
android:id="@+id/status_translate"
android:textColor="@color/mastodonC4"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout <LinearLayout
android:id="@+id/status_action_container" android:id="@+id/status_action_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="5dp"
android:padding="@dimen/drawer_padding" android:padding="@dimen/drawer_padding"
android:layout_marginStart="@dimen/activity_vertical_margin" android:layout_marginStart="@dimen/activity_vertical_margin"
android:layout_marginLeft="@dimen/activity_vertical_margin" android:layout_marginLeft="@dimen/activity_vertical_margin"

View File

@ -0,0 +1,52 @@
<?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>.
-->
<android.support.v7.widget.Toolbar 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/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:popupTheme="?attr/popupOverlay">
<ImageView
android:id="@+id/close_conversation"
android:src="@drawable/ic_close"
android:layout_width="30dp"
android:layout_height="30dp"
android:gravity="center_vertical"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/pp_actionBar"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:textColor="?attr/actionBarTextColor"
android:textSize="14sp"
android:id="@+id/toolbar_title" />
</android.support.v7.widget.Toolbar>

View File

@ -40,6 +40,12 @@
android:text="@string/set_share_validation" android:text="@string/set_share_validation"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_share_validation_fav"
android:layout_width="wrap_content"
android:text="@string/set_share_validation_fav"
android:layout_height="wrap_content" />
<CheckBox <CheckBox
android:id="@+id/set_show_error_messages" android:id="@+id/set_show_error_messages"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -58,11 +64,6 @@
android:text="@string/set_auto_store_toot" android:text="@string/set_auto_store_toot"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_bubble_counter"
android:layout_width="wrap_content"
android:text="@string/set_bubble_counter"
android:layout_height="wrap_content" />
<CheckBox <CheckBox
android:id="@+id/set_preview_reply" android:id="@+id/set_preview_reply"
@ -70,6 +71,18 @@
android:text="@string/set_preview_reply" android:text="@string/set_preview_reply"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_display_local"
android:layout_width="wrap_content"
android:text="@string/set_display_local"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_display_global"
android:layout_width="wrap_content"
android:text="@string/set_display_global"
android:layout_height="wrap_content" />
<LinearLayout <LinearLayout
android:id="@+id/set_preview_reply_pp_container" android:id="@+id/set_preview_reply_pp_container"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -93,7 +106,24 @@
/> />
</LinearLayout> </LinearLayout>
<!-- Translation engine -->
<LinearLayout
android:layout_marginTop="10dp"
android:id="@+id/translation_layout_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/about_yandex"/>
<Spinner
android:id="@+id/translation_layout_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -139,25 +169,7 @@
<!-- Translation engine -->
<LinearLayout
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:id="@+id/translation_layout_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/about_yandex"/>
<Spinner
android:id="@+id/translation_layout_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/set_javascript_container" android:id="@+id/set_javascript_container"

View File

@ -173,6 +173,25 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
/> />
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/set_led_colour_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:text="@string/set_led_colour"/>
<Spinner
android:id="@+id/led_colour_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/led_colours"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

Some files were not shown because too many files have changed in this diff Show More