Merge branch 'develop' into l10n_develop
This commit is contained in:
commit
bd87f76adb
|
@ -6,8 +6,8 @@ android {
|
|||
defaultConfig {
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 28
|
||||
versionCode 293
|
||||
versionName "2.10.2"
|
||||
versionCode 294
|
||||
versionName "2.10.3"
|
||||
multiDexEnabled true
|
||||
renderscriptTargetApi 28 as int
|
||||
renderscriptSupportModeEnabled true
|
||||
|
@ -55,7 +55,7 @@ allprojects {
|
|||
}
|
||||
}
|
||||
ext.supportLibraryVersion = '28.0.0'
|
||||
ext.glideLibraryVersion = '4.8.0'
|
||||
ext.glideLibraryVersion = '4.9.0'
|
||||
ext.conscryptLibraryVersion = '2.1.0'
|
||||
ext.evernoteLibraryVersion = '1.3.0-rc1'
|
||||
ext.gsonLibraryVersion = '2.8.2'
|
||||
|
@ -67,7 +67,7 @@ ext.uploadServiceVersion = "3.5.2"
|
|||
ext.torrentstreamVersion = "2.5.0"
|
||||
|
||||
ext.netCipherVersion = "2.0.0-alpha1"
|
||||
ext.acraVersion = "5.1.3"
|
||||
ext.acraVersion = "5.4.0"
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
|
@ -118,4 +118,6 @@ dependencies {
|
|||
implementation "ch.acra:acra-mail:$acraVersion"
|
||||
implementation "ch.acra:acra-limiter:$acraVersion"
|
||||
implementation "ch.acra:acra-notification:$acraVersion"
|
||||
implementation 'com.github.stom79:Android-WYSIWYG-Editor:3.2.1'
|
||||
implementation 'com.github.duanhong169:colorpicker:1.1.6'
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_COARSE_LOCATION"
|
||||
tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
@ -283,7 +285,7 @@
|
|||
android:fitsSystemWindows="true"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme_NoActionBar"
|
||||
android:theme="@style/AppTheme_NoActionBar_Fedilab"
|
||||
/>
|
||||
<activity android:name="app.fedilab.android.activities.EditProfileActivity"
|
||||
android:windowSoftInputMode="stateAlwaysHidden"
|
||||
|
|
|
@ -222,7 +222,7 @@ public abstract class BaseMainActivity extends BaseActivity
|
|||
final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -76,7 +76,7 @@ public class HashTagActivity extends BaseActivity implements OnRetrieveFeedsInte
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -79,7 +79,7 @@ public class ListActivity extends BaseActivity implements OnListActionInterface
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -70,7 +70,7 @@ public class ManageAccountsInListActivity extends BaseActivity implements OnList
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(ManageAccountsInListActivity.this, R.color.mastodonC3__));
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
|
|
|
@ -41,6 +41,7 @@ import android.widget.ImageView;
|
|||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
|
@ -546,7 +547,7 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface,
|
|||
loader.setVisibility(View.GONE);
|
||||
content_audio.setVisibility(View.VISIBLE);
|
||||
int color = getResources().getColor(R.color.mastodonC1);
|
||||
visualizerView = new GLAudioVisualizationView.Builder(this)
|
||||
visualizerView = new GLAudioVisualizationView.Builder(MediaActivity.this)
|
||||
.setLayersCount(1)
|
||||
.setWavesCount(6)
|
||||
.setWavesHeight(R.dimen.aar_wave_height)
|
||||
|
@ -594,7 +595,13 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface,
|
|||
playeraudio.prepare();
|
||||
playeraudio.start();
|
||||
|
||||
visualizerView.linkTo(DbmHandler.Factory.newVisualizerHandler(this, playeraudio));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) ==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
visualizerView.linkTo(DbmHandler.Factory.newVisualizerHandler(MediaActivity.this, playeraudio));
|
||||
}
|
||||
|
||||
}
|
||||
visualizerView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -718,7 +725,15 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface,
|
|||
@Override
|
||||
protected void onDestroy() {
|
||||
try {
|
||||
visualizerView.release();
|
||||
if( visualizerView != null) {
|
||||
visualizerView.release();
|
||||
}
|
||||
if( player != null) {
|
||||
player.release();
|
||||
}
|
||||
if( playeraudio != null) {
|
||||
playeraudio.release();
|
||||
}
|
||||
} catch (Exception ignored){ }
|
||||
super.onDestroy();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
@ -46,21 +45,26 @@ import android.widget.DatePicker;
|
|||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.asynctasks.RetrieveStatsAsyncTask;
|
||||
import app.fedilab.android.client.APIResponse;
|
||||
import app.fedilab.android.client.Entities.Account;
|
||||
import app.fedilab.android.client.Entities.Statistics;
|
||||
import app.fedilab.android.client.Entities.Status;
|
||||
import app.fedilab.android.drawers.StatusListAdapter;
|
||||
import app.fedilab.android.helper.FilterToots;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.interfaces.OnRetrieveStatsInterface;
|
||||
import app.fedilab.android.services.BackupStatusInDataBaseService;
|
||||
import app.fedilab.android.sqlite.AccountDAO;
|
||||
import app.fedilab.android.sqlite.Sqlite;
|
||||
|
@ -76,12 +80,11 @@ import app.fedilab.android.interfaces.OnRetrieveFeedsInterface;
|
|||
* Show owner's toots
|
||||
*/
|
||||
|
||||
public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeedsInterface {
|
||||
public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeedsInterface, OnRetrieveStatsInterface {
|
||||
|
||||
|
||||
private ImageView pp_actionBar;
|
||||
private StatusListAdapter statusListAdapter;
|
||||
private SharedPreferences sharedpreferences;
|
||||
private String max_id;
|
||||
private List<Status> statuses;
|
||||
private RelativeLayout mainLoader, nextElementLoader, textviewNoAction;
|
||||
|
@ -94,16 +97,19 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
private Button settings_time_from, settings_time_to;
|
||||
private FilterToots filterToots;
|
||||
private Date dateIni, dateEnd;
|
||||
private View statsDialogView;
|
||||
private Statistics statistics;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
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);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
@ -161,7 +167,6 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
firstLoad = true;
|
||||
swiped = false;
|
||||
boolean isOnWifi = Helper.isOnWIFI(OwnerStatusActivity.this);
|
||||
lv_status.addItemDecoration(new DividerItemDecoration(OwnerStatusActivity.this, DividerItemDecoration.VERTICAL));
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, null);
|
||||
statusListAdapter = new StatusListAdapter(OwnerStatusActivity.this, RetrieveFeedsAsyncTask.Type.CACHE_STATUS, userId, isOnWifi, this.statuses);
|
||||
|
@ -172,6 +177,8 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
|
||||
if( theme == Helper.THEME_DARK){
|
||||
style = R.style.DialogDark;
|
||||
}else if( theme == Helper.THEME_BLACK){
|
||||
style = R.style.DialogBlack;
|
||||
}else {
|
||||
style = R.style.Dialog;
|
||||
}
|
||||
|
@ -284,8 +291,9 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
case R.id.action_sync:
|
||||
Intent backupIntent = new Intent(OwnerStatusActivity.this, BackupStatusInDataBaseService.class);
|
||||
startService(backupIntent);
|
||||
statistics = null;
|
||||
return true;
|
||||
case R.id.action_filter:
|
||||
case R.id.action_stats:
|
||||
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_DARK) {
|
||||
|
@ -297,6 +305,35 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
}
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(OwnerStatusActivity.this, style);
|
||||
LayoutInflater inflater = this.getLayoutInflater();
|
||||
statsDialogView = inflater.inflate(R.layout.stats_owner_toots, null);
|
||||
dialogBuilder.setView(statsDialogView);
|
||||
dialogBuilder
|
||||
.setTitle(R.string.action_stats)
|
||||
.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
dialogBuilder.create().show();
|
||||
if( statistics == null) {
|
||||
new RetrieveStatsAsyncTask(getApplicationContext(), OwnerStatusActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}else{
|
||||
displayStats();
|
||||
}
|
||||
return true;
|
||||
case R.id.action_filter:
|
||||
sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
|
||||
theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
if (theme == Helper.THEME_DARK) {
|
||||
style = R.style.DialogDark;
|
||||
} else if (theme == Helper.THEME_BLACK){
|
||||
style = R.style.DialogBlack;
|
||||
}else {
|
||||
style = R.style.Dialog;
|
||||
}
|
||||
dialogBuilder = new AlertDialog.Builder(OwnerStatusActivity.this, style);
|
||||
inflater = this.getLayoutInflater();
|
||||
@SuppressLint("InflateParams") View dialogView = inflater.inflate(R.layout.filter_owner_toots, null);
|
||||
dialogBuilder.setView(dialogView);
|
||||
|
||||
|
@ -410,9 +447,7 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
final AlertDialog alertDialog = dialogBuilder.create();
|
||||
|
||||
alertDialog.show();
|
||||
dialogBuilder.create().show();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
@ -482,4 +517,57 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
|
|||
.unregisterReceiver(backupFinishedReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStats(Statistics statistics) {
|
||||
this.statistics = statistics;
|
||||
displayStats();
|
||||
}
|
||||
|
||||
private void displayStats(){
|
||||
if( statsDialogView != null){
|
||||
ScrollView stats_container = statsDialogView.findViewById(R.id.stats_container);
|
||||
RelativeLayout loader = statsDialogView.findViewById(R.id.loader);
|
||||
|
||||
TextView total_statuses = statsDialogView.findViewById(R.id.total_statuses);
|
||||
TextView number_boosts = statsDialogView.findViewById(R.id.number_boosts);
|
||||
TextView number_replies = statsDialogView.findViewById(R.id.number_replies);
|
||||
TextView number_statuses = statsDialogView.findViewById(R.id.number_statuses);
|
||||
TextView number_with_media = statsDialogView.findViewById(R.id.number_with_media);
|
||||
TextView number_with_cw = statsDialogView.findViewById(R.id.number_with_cw);
|
||||
TextView number_with_sensitive_media = statsDialogView.findViewById(R.id.number_with_sensitive_media);
|
||||
TextView v_public = statsDialogView.findViewById(R.id.v_public);
|
||||
TextView v_unlisted = statsDialogView.findViewById(R.id.v_unlisted);
|
||||
TextView v_private = statsDialogView.findViewById(R.id.v_private);
|
||||
TextView v_direct = statsDialogView.findViewById(R.id.v_direct);
|
||||
|
||||
TextView frequency = statsDialogView.findViewById(R.id.frequency);
|
||||
TextView last_toot_date = statsDialogView.findViewById(R.id.last_toot_date);
|
||||
TextView first_toot_date = statsDialogView.findViewById(R.id.first_toot_date);
|
||||
|
||||
|
||||
total_statuses.setText(String.valueOf(statistics.getTotal_statuses()));
|
||||
number_boosts.setText(String.valueOf(statistics.getNumber_boosts()));
|
||||
number_replies.setText(String.valueOf(statistics.getNumber_replies()));
|
||||
number_statuses.setText(String.valueOf(statistics.getNumber_status()));
|
||||
number_with_media.setText(String.valueOf(statistics.getNumber_with_media()));
|
||||
number_with_cw.setText(String.valueOf(statistics.getNumber_with_cw()));
|
||||
number_with_sensitive_media.setText(String.valueOf(statistics.getNumber_with_sensitive_media()));
|
||||
v_public.setText(String.valueOf(statistics.getV_public()));
|
||||
v_unlisted.setText(String.valueOf(statistics.getV_unlisted()));
|
||||
v_private.setText(String.valueOf(statistics.getV_private()));
|
||||
v_direct.setText(String.valueOf(statistics.getV_direct()));
|
||||
|
||||
|
||||
first_toot_date.setText(Helper.dateToString(statistics.getFirstTootDate()));
|
||||
last_toot_date.setText(Helper.dateToString(statistics.getLastTootDate()));
|
||||
DecimalFormat df = new DecimalFormat("#.##");
|
||||
frequency.setText(getString(R.string.toot_per_day, df.format(statistics.getFrequency())));
|
||||
|
||||
stats_container.setVisibility(View.VISIBLE);
|
||||
loader.setVisibility(View.GONE);
|
||||
|
||||
}else{
|
||||
Toasty.error(OwnerStatusActivity.this,getString(R.string.toast_error),Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public class PlaylistsActivity extends BaseActivity implements OnPlaylistActionI
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -52,7 +52,7 @@ public class ProxyActivity extends BaseActivity {
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(ProxyActivity.this, R.color.mastodonC3__));
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
|
|
|
@ -72,7 +72,7 @@ public class SettingsActivity extends BaseActivity implements ViewAnimator.ViewA
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -156,7 +156,7 @@ public class ShowAccountActivity extends BaseActivity implements OnPostActionInt
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -86,7 +86,7 @@ public class ShowConversationActivity extends BaseActivity implements OnRetriev
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
@ -402,7 +402,7 @@ public class ShowConversationActivity extends BaseActivity implements OnRetriev
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -60,7 +60,7 @@ public class TagCacheActivity extends BaseActivity {
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(TagCacheActivity.this, R.color.mastodonC3__));
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -77,7 +77,7 @@ public class WhoToFollowActivity extends BaseActivity implements OnRetrieveWhoTo
|
|||
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
|
||||
switch (theme){
|
||||
case Helper.THEME_LIGHT:
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
|
||||
break;
|
||||
case Helper.THEME_DARK:
|
||||
setTheme(R.style.AppThemeDark_NoActionBar);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* Copyright 2019 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
package app.fedilab.android.asynctasks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.AsyncTask;
|
||||
import java.lang.ref.WeakReference;
|
||||
import app.fedilab.android.client.Entities.Statistics;
|
||||
import app.fedilab.android.interfaces.OnRetrieveStatsInterface;
|
||||
import app.fedilab.android.sqlite.Sqlite;
|
||||
import app.fedilab.android.sqlite.StatusCacheDAO;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Thomas on 23/07/2019.
|
||||
* Retrieves stats for an account
|
||||
*/
|
||||
|
||||
public class RetrieveStatsAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
|
||||
private OnRetrieveStatsInterface listener;
|
||||
private WeakReference<Context> contextReference;
|
||||
private Statistics statistics;
|
||||
|
||||
public RetrieveStatsAsyncTask(Context context, OnRetrieveStatsInterface onRetrieveStatsInterface){
|
||||
this.contextReference = new WeakReference<>(context);
|
||||
this.listener = onRetrieveStatsInterface;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
|
||||
SQLiteDatabase db = Sqlite.getInstance(contextReference.get(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
statistics = new StatusCacheDAO(contextReference.get(), db).getStat();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
listener.onStats(statistics);
|
||||
}
|
||||
|
||||
}
|
|
@ -28,6 +28,7 @@ import app.fedilab.android.client.APIResponse;
|
|||
import app.fedilab.android.client.Entities.ManageTimelines;
|
||||
import app.fedilab.android.client.Entities.RemoteInstance;
|
||||
import app.fedilab.android.client.Entities.TagTimeline;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.sqlite.InstancesDAO;
|
||||
import app.fedilab.android.sqlite.SearchDAO;
|
||||
import app.fedilab.android.sqlite.Sqlite;
|
||||
|
@ -243,10 +244,13 @@ public class SyncTimelinesAsyncTask extends AsyncTask<Void, Void, Void> {
|
|||
}
|
||||
}
|
||||
}
|
||||
APIResponse apiResponse = null;
|
||||
List<app.fedilab.android.client.Entities.List> lists = null;
|
||||
try {
|
||||
apiResponse = new API(contextReference.get()).getLists();
|
||||
lists = apiResponse.getLists();
|
||||
}catch (Exception ignored){ }
|
||||
|
||||
|
||||
APIResponse apiResponse = new API(contextReference.get()).getLists();
|
||||
List<app.fedilab.android.client.Entities.List> lists = apiResponse.getLists();
|
||||
if( lists != null && lists.size() > 0){
|
||||
//Loop through results
|
||||
for(app.fedilab.android.client.Entities.List list: lists){
|
||||
|
@ -287,6 +291,12 @@ public class SyncTimelinesAsyncTask extends AsyncTask<Void, Void, Void> {
|
|||
new TimelinesDAO(contextReference.get(), db).remove(manageTimelines);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for(ManageTimelines manageTimelines: manageTimelines){
|
||||
if( manageTimelines.getListTimeline() == null )
|
||||
continue;
|
||||
new TimelinesDAO(contextReference.get(), db).remove(manageTimelines);
|
||||
}
|
||||
}
|
||||
|
||||
for (Iterator<ManageTimelines> it = manageTimelines.iterator(); it.hasNext();) {
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.os.Bundle;
|
|||
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.room.util.StringUtil;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
@ -48,9 +47,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.activities.LoginActivity;
|
||||
import app.fedilab.android.activities.MainActivity;
|
||||
import app.fedilab.android.asynctasks.PostAdminActionAsyncTask;
|
||||
import app.fedilab.android.asynctasks.RetrieveOpenCollectiveAsyncTask;
|
||||
import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask;
|
||||
import app.fedilab.android.client.Entities.Account;
|
||||
|
@ -2810,6 +2807,36 @@ public class API {
|
|||
return actionCode;
|
||||
}
|
||||
|
||||
public int reportStatus(List<Status> statuses, String comment, boolean forward){
|
||||
String action;
|
||||
HashMap<String, String> params = null;
|
||||
action = "/reports";
|
||||
params = new HashMap<>();
|
||||
params.put("account_id", statuses.get(0).getAccount().getId());
|
||||
params.put("comment", comment);
|
||||
StringBuilder parameters = new StringBuilder();
|
||||
for(Status val: statuses)
|
||||
parameters.append("status_ids[]=").append(val).append("&");
|
||||
if( parameters.length() > 0) {
|
||||
parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1).substring(13));
|
||||
params.put("status_ids[]", parameters.toString());
|
||||
}
|
||||
params.put("forward", String.valueOf(forward));
|
||||
try {
|
||||
HttpsConnection httpsConnection = new HttpsConnection(context, this.instance);
|
||||
httpsConnection.post(getAbsoluteUrl(action), 10, params, prefKeyOauthTokenT);
|
||||
actionCode = httpsConnection.getActionCode();
|
||||
} catch (HttpsConnection.HttpsConnectionException e) {
|
||||
setError(e.getStatusCode(), e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (KeyManagementException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
package app.fedilab.android.client.Entities;
|
||||
/* Copyright 2019 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Statistics {
|
||||
|
||||
|
||||
private int total_statuses = 0;
|
||||
private int number_boosts = 0;
|
||||
private int number_replies = 0;
|
||||
private int number_status = 0;
|
||||
private int number_with_media = 0;
|
||||
private int number_with_cw = 0;
|
||||
private int number_with_sensitive_media = 0;
|
||||
private int v_public = 0;
|
||||
private int v_unlisted = 0;
|
||||
private int v_private = 0;
|
||||
private Date firstTootDate;
|
||||
private Date lastTootDate;
|
||||
private float frequency;
|
||||
|
||||
|
||||
public Date getFirstTootDate() {
|
||||
return firstTootDate;
|
||||
}
|
||||
|
||||
public void setFirstTootDate(Date firstTootDate) {
|
||||
this.firstTootDate = firstTootDate;
|
||||
}
|
||||
|
||||
public Date getLastTootDate() {
|
||||
return lastTootDate;
|
||||
}
|
||||
|
||||
public void setLastTootDate(Date lastTootDate) {
|
||||
this.lastTootDate = lastTootDate;
|
||||
}
|
||||
|
||||
public float getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public void setFrequency(float frequency) {
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
public int getTotal_statuses() {
|
||||
return total_statuses;
|
||||
}
|
||||
|
||||
public void setTotal_statuses(int total_statuses) {
|
||||
this.total_statuses = total_statuses;
|
||||
}
|
||||
|
||||
public int getNumber_boosts() {
|
||||
return number_boosts;
|
||||
}
|
||||
|
||||
public void setNumber_boosts(int number_boosts) {
|
||||
this.number_boosts = number_boosts;
|
||||
}
|
||||
|
||||
public int getNumber_replies() {
|
||||
return number_replies;
|
||||
}
|
||||
|
||||
public void setNumber_replies(int number_replies) {
|
||||
this.number_replies = number_replies;
|
||||
}
|
||||
|
||||
public int getNumber_status() {
|
||||
return number_status;
|
||||
}
|
||||
|
||||
public void setNumber_status(int number_status) {
|
||||
this.number_status = number_status;
|
||||
}
|
||||
|
||||
public int getNumber_with_media() {
|
||||
return number_with_media;
|
||||
}
|
||||
|
||||
public void setNumber_with_media(int number_with_media) {
|
||||
this.number_with_media = number_with_media;
|
||||
}
|
||||
|
||||
public int getNumber_with_cw() {
|
||||
return number_with_cw;
|
||||
}
|
||||
|
||||
public void setNumber_with_cw(int number_with_cw) {
|
||||
this.number_with_cw = number_with_cw;
|
||||
}
|
||||
|
||||
public int getNumber_with_sensitive_media() {
|
||||
return number_with_sensitive_media;
|
||||
}
|
||||
|
||||
public void setNumber_with_sensitive_media(int number_with_sensitive_media) {
|
||||
this.number_with_sensitive_media = number_with_sensitive_media;
|
||||
}
|
||||
|
||||
public int getV_public() {
|
||||
return v_public;
|
||||
}
|
||||
|
||||
public void setV_public(int v_public) {
|
||||
this.v_public = v_public;
|
||||
}
|
||||
|
||||
public int getV_unlisted() {
|
||||
return v_unlisted;
|
||||
}
|
||||
|
||||
public void setV_unlisted(int v_unlisted) {
|
||||
this.v_unlisted = v_unlisted;
|
||||
}
|
||||
|
||||
public int getV_private() {
|
||||
return v_private;
|
||||
}
|
||||
|
||||
public void setV_private(int v_private) {
|
||||
this.v_private = v_private;
|
||||
}
|
||||
|
||||
public int getV_direct() {
|
||||
return v_direct;
|
||||
}
|
||||
|
||||
public void setV_direct(int v_direct) {
|
||||
this.v_direct = v_direct;
|
||||
}
|
||||
|
||||
private int v_direct;
|
||||
}
|
|
@ -70,6 +70,7 @@ import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask;
|
|||
import app.fedilab.android.helper.CrossActions;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.interfaces.OnRetrieveEmojiInterface;
|
||||
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
|
||||
|
||||
import static app.fedilab.android.helper.Helper.THEME_BLACK;
|
||||
import static app.fedilab.android.helper.Helper.THEME_DARK;
|
||||
|
@ -112,6 +113,7 @@ public class Status implements Parcelable{
|
|||
private String language;
|
||||
private boolean isTranslated = false;
|
||||
private boolean isEmojiFound = false;
|
||||
private boolean isImageFound = false;
|
||||
private boolean isEmojiTranslateFound = false;
|
||||
private boolean isClickable = false;
|
||||
private boolean isTranslationShown = false;
|
||||
|
@ -144,6 +146,7 @@ public class Status implements Parcelable{
|
|||
private boolean shortReply = false;
|
||||
|
||||
private int warningFetched = -1;
|
||||
private List<String> imageURL;
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
|
@ -207,6 +210,7 @@ public class Status implements Parcelable{
|
|||
dest.writeByte(this.customFeaturesDisplayed ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.shortReply ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.warningFetched);
|
||||
dest.writeStringList(this.imageURL);
|
||||
}
|
||||
|
||||
protected Status(Parcel in) {
|
||||
|
@ -272,6 +276,7 @@ public class Status implements Parcelable{
|
|||
this.customFeaturesDisplayed = in.readByte() != 0;
|
||||
this.shortReply = in.readByte() != 0;
|
||||
this.warningFetched = in.readInt();
|
||||
this.imageURL = in.createStringArrayList();
|
||||
}
|
||||
|
||||
public static final Creator<Status> CREATOR = new Creator<Status>() {
|
||||
|
@ -559,6 +564,9 @@ public class Status implements Parcelable{
|
|||
return isEmojiFound;
|
||||
}
|
||||
|
||||
public boolean isImageFound() {
|
||||
return isImageFound;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -567,6 +575,10 @@ public class Status implements Parcelable{
|
|||
isEmojiFound = emojiFound;
|
||||
}
|
||||
|
||||
public void setImageFound(boolean imageFound) {
|
||||
isImageFound = imageFound;
|
||||
}
|
||||
|
||||
|
||||
public static void transform(Context context, Status status){
|
||||
|
||||
|
@ -605,7 +617,54 @@ public class Status implements Parcelable{
|
|||
content = content.replaceFirst(Pattern.quote(beforemodification), Matcher.quoteReplacement(urlText));
|
||||
}
|
||||
}
|
||||
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
|
||||
Matcher matcher = imgPattern.matcher(content);
|
||||
List<String> imgs = new ArrayList<>();
|
||||
int i = 1;
|
||||
while (matcher.find()) {
|
||||
content = content.replaceAll(Pattern.quote(matcher.group(0)), "<br/>[media_"+i+"]<br/>");
|
||||
imgs.add("[media_"+i+"]|"+matcher.group(1));
|
||||
i++;
|
||||
}
|
||||
status.setImageURL(imgs);
|
||||
spannableStringContent = new SpannableString(content);
|
||||
final int[] j = {0};
|
||||
if( status.getImageURL() != null && status.getImageURL().size() > 0){
|
||||
for(String val: status.getImageURL()){
|
||||
String[] valArray = val.split("\\|");
|
||||
if( valArray.length > 1 ){
|
||||
String contentOriginal = valArray[0];
|
||||
String url = valArray[1];
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.into(new SimpleTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||
final String targetedEmoji = contentOriginal;
|
||||
if (spannableStringContent != null && spannableStringContent.toString().contains(targetedEmoji)) {
|
||||
//emojis can be used several times so we have to loop
|
||||
for (int startPosition = -1; (startPosition = spannableStringContent.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
||||
final int endPosition = startPosition + targetedEmoji.length();
|
||||
if( endPosition <= spannableStringContent.toString().length() && endPosition >= startPosition) {
|
||||
spannableStringContent.setSpan(
|
||||
new ImageSpan(context,
|
||||
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(300, context),
|
||||
(int) Helper.convertDpToPixel(300, context), false)), startPosition,
|
||||
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
j[0]++;
|
||||
if( j[0] == (status.getImageURL().size())) {
|
||||
status.setContentSpan(spannableStringContent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
String spoilerText = "";
|
||||
if( status.getReblog() != null && status.getReblog().getSpoiler_text() != null)
|
||||
spoilerText = status.getReblog().getSpoiler_text();
|
||||
|
@ -704,6 +763,9 @@ public class Status implements Parcelable{
|
|||
accountsMentionUnknown.put(key, account);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SpannableString spannableStringT;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
spannableStringT = new SpannableString(Html.fromHtml(spannableString.toString().replaceAll("^<p>","").replaceAll("<p>","<br/><br/>").replaceAll("</p>","").replaceAll("<br />","<br/>").replaceAll("[\\s]{2}"," "), Html.FROM_HTML_MODE_LEGACY));
|
||||
|
@ -1057,6 +1119,75 @@ public class Status implements Parcelable{
|
|||
}
|
||||
|
||||
|
||||
public static void makeImage(final Context context, final OnRetrieveImageInterface listener, Status status){
|
||||
|
||||
if( ((Activity)context).isFinishing() )
|
||||
return;
|
||||
if( status.getAccount() == null)
|
||||
return;
|
||||
if( status.getImageURL() == null || status.getImageURL().size() == 0)
|
||||
return;
|
||||
|
||||
SpannableString contentSpan = status.getContentSpan();
|
||||
|
||||
final int[] i = {0};
|
||||
for (final String img : status.getImageURL()) {
|
||||
final String name = img.split("\\|")[0];
|
||||
final String imgURL = img.split("\\|")[1];
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(imgURL)
|
||||
.listener(new RequestListener<Bitmap>() {
|
||||
@Override
|
||||
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
|
||||
i[0]++;
|
||||
if( i[0] == (status.getImageURL().size())) {
|
||||
listener.onRetrieveImage(status,false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.into(new SimpleTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||
|
||||
int w = resource.getWidth();
|
||||
int h = resource.getHeight();
|
||||
if( w > 300 ){
|
||||
h = (h * 300) / w;
|
||||
w = 300;
|
||||
}
|
||||
final String targetedEmoji = name;
|
||||
if (contentSpan != null && contentSpan.toString().contains(targetedEmoji)) {
|
||||
//emojis can be used several times so we have to loop
|
||||
for (int startPosition = -1; (startPosition = contentSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
||||
final int endPosition = startPosition + targetedEmoji.length();
|
||||
if( endPosition <= contentSpan.toString().length() && endPosition >= startPosition)
|
||||
contentSpan.setSpan(
|
||||
new ImageSpan(context,
|
||||
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(w, context),
|
||||
(int) Helper.convertDpToPixel(h, context), false)), startPosition,
|
||||
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
i[0]++;
|
||||
if( i[0] == (status.getImageURL().size())) {
|
||||
status.setContentSpan(contentSpan);
|
||||
status.setImageFound(true);
|
||||
listener.onRetrieveImage(status, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void makeEmojisTranslation(final Context context, final OnRetrieveEmojiInterface listener, Status status){
|
||||
|
||||
if( ((Activity)context).isFinishing() )
|
||||
|
@ -1383,4 +1514,12 @@ public class Status implements Parcelable{
|
|||
public void setWarningFetched(int warningFetched) {
|
||||
this.warningFetched = warningFetched;
|
||||
}
|
||||
|
||||
public List<String> getImageURL() {
|
||||
return imageURL;
|
||||
}
|
||||
|
||||
public void setImageURL(List<String> imageURL) {
|
||||
this.imageURL = imageURL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package app.fedilab.android.client.Entities;
|
||||
/* Copyright 2019 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
public class Suggestion {
|
||||
|
||||
private String content;
|
||||
private String imageUrl;
|
||||
private suggestionType type;
|
||||
|
||||
public enum suggestionType{
|
||||
TAG,
|
||||
ACCOUNT,
|
||||
EMOJI
|
||||
}
|
||||
|
||||
public suggestionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(suggestionType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ import app.fedilab.android.client.Entities.Status;
|
|||
import app.fedilab.android.helper.CrossActions;
|
||||
import app.fedilab.android.helper.CustomTextView;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
|
||||
import br.com.felix.horizontalbargraph.HorizontalBar;
|
||||
import br.com.felix.horizontalbargraph.model.BarItem;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
@ -108,7 +109,7 @@ import static app.fedilab.android.helper.Helper.changeDrawableColor;
|
|||
* Adapter for Status
|
||||
*/
|
||||
|
||||
public class NotificationsListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnPostNotificationsActionInterface, OnRetrieveEmojiInterface, OnRetrieveEmojiAccountInterface, OnPollInterface {
|
||||
public class NotificationsListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnPostNotificationsActionInterface, OnRetrieveEmojiInterface, OnRetrieveEmojiAccountInterface, OnPollInterface, OnRetrieveImageInterface {
|
||||
|
||||
private Context context;
|
||||
private List<Notification> notifications;
|
||||
|
@ -376,6 +377,8 @@ public class NotificationsListAdapter extends RecyclerView.Adapter implements On
|
|||
Status.transform(context, status);
|
||||
if( !status.isEmojiFound())
|
||||
Notification.makeEmojis(context, NotificationsListAdapter.this, notification);
|
||||
if( !status.isImageFound())
|
||||
Status.makeImage(context, NotificationsListAdapter.this, status);
|
||||
holder.notification_status_content.setText(status.getContentSpan(), TextView.BufferType.SPANNABLE);
|
||||
holder.status_spoiler.setText(status.getContentSpanCW(), TextView.BufferType.SPANNABLE);
|
||||
holder.status_spoiler.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
@ -1344,6 +1347,14 @@ public class NotificationsListAdapter extends RecyclerView.Adapter implements On
|
|||
notifyNotificationWithActionChanged(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRetrieveImage(Status status, boolean fromTranslation) {
|
||||
if( status != null ) {
|
||||
status.setEmojiFound(true);
|
||||
notifyNotificationWithActionChanged(status);
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
FrameLayout card_status_container;
|
||||
|
|
|
@ -133,6 +133,7 @@ import app.fedilab.android.helper.CustomTextView;
|
|||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastalabAutoCompleteTextView;
|
||||
import app.fedilab.android.interfaces.OnPostStatusActionInterface;
|
||||
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
|
||||
import app.fedilab.android.interfaces.OnRetrieveRelationshipInterface;
|
||||
import app.fedilab.android.interfaces.OnRetrieveRelationshipQuickReplyInterface;
|
||||
import app.fedilab.android.interfaces.OnRetrieveSearcAccountshInterface;
|
||||
|
@ -185,7 +186,7 @@ import static app.fedilab.android.helper.Helper.changeDrawableColor;
|
|||
* Created by Thomas on 24/04/2017.
|
||||
* Adapter for Status
|
||||
*/
|
||||
public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface, OnPollInterface, OnRefreshCachedStatusInterface, OnRetrieveSearcAccountshInterface, OnRetrieveSearchInterface, OnPostStatusActionInterface, OnRetrieveRelationshipQuickReplyInterface {
|
||||
public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveImageInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface, OnPollInterface, OnRefreshCachedStatusInterface, OnRetrieveSearcAccountshInterface, OnRetrieveSearchInterface, OnPostStatusActionInterface, OnRetrieveRelationshipQuickReplyInterface {
|
||||
|
||||
private Context context;
|
||||
private List<Status> statuses;
|
||||
|
@ -528,7 +529,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
|||
if( error != null){
|
||||
return;
|
||||
}
|
||||
if( relationship.isBlocked_by() ){
|
||||
if( relationship != null && relationship.isBlocked_by() ){
|
||||
warning_message.setVisibility(View.VISIBLE);
|
||||
status.setWarningFetched(1);
|
||||
}else{
|
||||
|
@ -537,6 +538,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
|||
}
|
||||
|
||||
|
||||
|
||||
private class ViewHolderEmpty extends RecyclerView.ViewHolder{
|
||||
ViewHolderEmpty(View itemView) {
|
||||
super(itemView);
|
||||
|
@ -1457,6 +1459,9 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
|||
Status.transform(context, status);
|
||||
if (!status.isEmojiFound())
|
||||
Status.makeEmojis(context, this, status);
|
||||
if (!status.isImageFound())
|
||||
Status.makeImage(context, this, status);
|
||||
|
||||
holder.status_content.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
|
@ -4110,6 +4115,19 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRetrieveImage(Status status, boolean fromTranslation) {
|
||||
if( status != null) {
|
||||
if( !fromTranslation) {
|
||||
status.setImageFound(true);
|
||||
}else {
|
||||
status.setImageFound(true);
|
||||
}
|
||||
notifyStatusChanged(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRetrieveEmoji(Status status, boolean fromTranslation) {
|
||||
if( status != null) {
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package app.fedilab.android.drawers;
|
||||
/* Copyright 2019 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.List;
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.client.Entities.Suggestion;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Thomas on 19/07/2019.
|
||||
* Adapter for suggestions results
|
||||
*/
|
||||
public class SuggestionsAdapter extends RecyclerView.Adapter {
|
||||
|
||||
private Context context;
|
||||
private List<Suggestion> suggestions;
|
||||
|
||||
private LayoutInflater layoutInflater;
|
||||
|
||||
public SuggestionsAdapter(Context context, List<Suggestion> suggestions){
|
||||
this.context = context;
|
||||
this.suggestions = suggestions;
|
||||
layoutInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
|
||||
public Suggestion getItem(int position) {
|
||||
return suggestions.get(position);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
|
||||
return new ViewHolder(layoutInflater.inflate(R.layout.drawer_suggestions, parent, false));
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder{
|
||||
private TextView suggestion_content;
|
||||
private ImageView suggestion_image;
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
suggestion_content = itemView.findViewById(R.id.suggestion_content);
|
||||
suggestion_image = itemView.findViewById(R.id.suggestion_image);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
|
||||
final ViewHolder holder = (ViewHolder) viewHolder;
|
||||
final Suggestion suggestion = getItem(i);
|
||||
|
||||
if( suggestion.getType() == Suggestion.suggestionType.TAG) {
|
||||
holder.suggestion_content.setText(String.format("#%s", suggestion.getContent()));
|
||||
holder.suggestion_image.setVisibility(View.GONE);
|
||||
}else{
|
||||
holder.suggestion_content.setText(suggestion.getContent());
|
||||
Helper.loadGiF(context, suggestion.getImageUrl(), holder.suggestion_image);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return suggestions.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -67,6 +67,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||
import com.google.android.material.navigation.NavigationView;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.apache.poi.sl.usermodel.Line;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -1042,6 +1043,25 @@ public class ContentSettingsFragment extends Fragment implements ScreenShotable
|
|||
});
|
||||
|
||||
|
||||
if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.PLEROMA) {
|
||||
LinearLayout set_wysiwyg_container = rootView.findViewById(R.id.set_wysiwyg_container);
|
||||
set_wysiwyg_container.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
boolean wysiwyg = sharedpreferences.getBoolean(Helper.SET_WYSIWYG, true);
|
||||
final CheckBox set_wysiwyg = rootView.findViewById(R.id.set_wysiwyg);
|
||||
set_wysiwyg.setChecked(wysiwyg);
|
||||
|
||||
set_wysiwyg.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putBoolean(Helper.SET_WYSIWYG, set_wysiwyg.isChecked());
|
||||
editor.apply();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
final CheckBox set_embedded_browser = rootView.findViewById(R.id.set_embedded_browser);
|
||||
final LinearLayout set_javascript_container = rootView.findViewById(R.id.set_javascript_container);
|
||||
final CheckBox set_custom_tabs = rootView.findViewById(R.id.set_custom_tabs);
|
||||
|
@ -1455,7 +1475,7 @@ public class ContentSettingsFragment extends Fragment implements ScreenShotable
|
|||
ArrayAdapter<CharSequence> adapterResize = ArrayAdapter.createFromResource(getContext(),
|
||||
R.array.settings_resize_picture, android.R.layout.simple_spinner_item);
|
||||
resize_layout_spinner.setAdapter(adapterResize);
|
||||
int positionSpinnerResize = sharedpreferences.getInt(Helper.SET_PICTURE_RESIZE, Helper.S_NO);
|
||||
int positionSpinnerResize = sharedpreferences.getInt(Helper.SET_PICTURE_RESIZE, Helper.S_4MO);
|
||||
resize_layout_spinner.setSelection(positionSpinnerResize);
|
||||
resize_layout_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
|
|
|
@ -206,6 +206,8 @@ import app.fedilab.android.client.Entities.Version;
|
|||
import app.fedilab.android.client.Tls12SocketFactory;
|
||||
import app.fedilab.android.fragments.DisplayMutedInstanceFragment;
|
||||
import app.fedilab.android.sqlite.DomainBlockDAO;
|
||||
import app.fedilab.android.sqlite.StatusCacheDAO;
|
||||
import app.fedilab.android.sqlite.TimelineCacheDAO;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
import app.fedilab.android.BuildConfig;
|
||||
import app.fedilab.android.R;
|
||||
|
@ -339,6 +341,7 @@ public class Helper {
|
|||
public static final String SET_LIVE_NOTIFICATIONS = "set_live_notifications";
|
||||
public static final String SET_DISABLE_GIF = "set_disable_gif";
|
||||
public static final String SET_CAPITALIZE = "set_capitalize";
|
||||
public static final String SET_WYSIWYG = "set_wysiwyg";
|
||||
public static final String SET_PICTURE_RESIZE = "set_picture_resize";
|
||||
public static final String SET_FORWARD_TAGS_IN_REPLY = "set_forward_tags_in_reply";
|
||||
public static final String SET_FULL_PREVIEW = "set_full_preview";
|
||||
|
@ -2064,14 +2067,17 @@ public class Helper {
|
|||
if( directory == null || directory.length() == 0 )
|
||||
return -1;
|
||||
for (File file : directory.listFiles()) {
|
||||
if (file.isFile())
|
||||
if (file.isFile()){
|
||||
try {
|
||||
length += file.length();
|
||||
}catch (NullPointerException e){
|
||||
} catch (NullPointerException e) {
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
length += cacheSize(file);
|
||||
}else {
|
||||
if( !file.getName().equals("databases") && !file.getName().equals("shared_prefs")) {
|
||||
length += cacheSize(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
@ -3196,78 +3202,99 @@ public class Helper {
|
|||
PROFILE
|
||||
}
|
||||
|
||||
|
||||
public static ByteArrayInputStream compressImage(Context context, android.net.Uri uriFile, MediaType mediaType){
|
||||
Bitmap takenImage;
|
||||
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
String mime = cr.getType(uriFile);
|
||||
ByteArrayInputStream bs = null;
|
||||
try {
|
||||
takenImage = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uriFile);
|
||||
} catch (IOException e) {
|
||||
if(mime != null && mime.toLowerCase().contains("image")){
|
||||
Bitmap takenImage;
|
||||
try {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}catch (Exception ignored){};
|
||||
return null;
|
||||
}
|
||||
ExifInterface exif = null;
|
||||
try (InputStream inputStream = context.getContentResolver().openInputStream(uriFile)) {
|
||||
assert inputStream != null;
|
||||
exif = new ExifInterface(inputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Matrix matrix = null;
|
||||
if( takenImage != null ){
|
||||
int size = takenImage.getByteCount();
|
||||
if( exif != null) {
|
||||
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
int rotationDegree = 0;
|
||||
if (rotation == ExifInterface.ORIENTATION_ROTATE_90) { rotationDegree = 90; }
|
||||
else if (rotation == ExifInterface.ORIENTATION_ROTATE_180) { rotationDegree = 180; }
|
||||
else if (rotation == ExifInterface.ORIENTATION_ROTATE_270) { rotationDegree = 270; }
|
||||
matrix = new Matrix();
|
||||
if (rotation != 0f) {matrix.preRotate(rotationDegree);}
|
||||
takenImage = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uriFile);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}catch (Exception ignored){};
|
||||
return null;
|
||||
}
|
||||
|
||||
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
|
||||
int resizeSet = sharedpreferences.getInt(Helper.SET_PICTURE_RESIZE, Helper.S_NO);
|
||||
if( mediaType == MediaType.PROFILE)
|
||||
resizeSet = Helper.S_1MO;
|
||||
double resizeby = size;
|
||||
if( resizeSet == Helper.S_512KO){
|
||||
resizeby = 4194304;
|
||||
}else if(resizeSet == Helper.S_1MO){
|
||||
resizeby = 8388608;
|
||||
}else if(resizeSet == Helper.S_2MO){
|
||||
resizeby = 16777216;
|
||||
}else if(resizeSet == Helper.S_4MO){
|
||||
resizeby = 33554432;
|
||||
}else if(resizeSet == Helper.S_6MO){
|
||||
resizeby = 50331648;
|
||||
}else if(resizeSet == Helper.S_8MO) {
|
||||
resizeby = 67108864;
|
||||
ExifInterface exif = null;
|
||||
try (InputStream inputStream = context.getContentResolver().openInputStream(uriFile)) {
|
||||
assert inputStream != null;
|
||||
exif = new ExifInterface(inputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Matrix matrix = null;
|
||||
if( takenImage != null ){
|
||||
int size = takenImage.getByteCount();
|
||||
if( exif != null) {
|
||||
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
int rotationDegree = 0;
|
||||
if (rotation == ExifInterface.ORIENTATION_ROTATE_90) { rotationDegree = 90; }
|
||||
else if (rotation == ExifInterface.ORIENTATION_ROTATE_180) { rotationDegree = 180; }
|
||||
else if (rotation == ExifInterface.ORIENTATION_ROTATE_270) { rotationDegree = 270; }
|
||||
matrix = new Matrix();
|
||||
if (rotation != 0f) {matrix.preRotate(rotationDegree);}
|
||||
}
|
||||
|
||||
double resize = ((double)size)/resizeby;
|
||||
if( resize > 1 ){
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
String mime = cr.getType(uriFile);
|
||||
Bitmap newBitmap = Bitmap.createScaledBitmap(takenImage, (int) (takenImage.getWidth() / resize),
|
||||
(int) (takenImage.getHeight() / resize), true);
|
||||
Bitmap adjustedBitmap;
|
||||
if( matrix != null)
|
||||
try {
|
||||
adjustedBitmap = Bitmap.createBitmap(newBitmap, 0, 0, newBitmap.getWidth(), newBitmap.getHeight(), matrix, true);
|
||||
}catch (Exception e){
|
||||
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
|
||||
int resizeSet = sharedpreferences.getInt(Helper.SET_PICTURE_RESIZE, Helper.S_4MO);
|
||||
if( mediaType == MediaType.PROFILE)
|
||||
resizeSet = Helper.S_1MO;
|
||||
double resizeby = size;
|
||||
if( resizeSet == Helper.S_512KO){
|
||||
resizeby = 4194304;
|
||||
}else if(resizeSet == Helper.S_1MO){
|
||||
resizeby = 8388608;
|
||||
}else if(resizeSet == Helper.S_2MO){
|
||||
resizeby = 16777216;
|
||||
}else if(resizeSet == Helper.S_4MO){
|
||||
resizeby = 33554432;
|
||||
}else if(resizeSet == Helper.S_6MO){
|
||||
resizeby = 50331648;
|
||||
}else if(resizeSet == Helper.S_8MO) {
|
||||
resizeby = 67108864;
|
||||
}
|
||||
|
||||
double resize = ((double)size)/resizeby;
|
||||
if( resize > 1 ){
|
||||
Bitmap newBitmap = Bitmap.createScaledBitmap(takenImage, (int) (takenImage.getWidth() / resize),
|
||||
(int) (takenImage.getHeight() / resize), true);
|
||||
Bitmap adjustedBitmap;
|
||||
if( matrix != null)
|
||||
try {
|
||||
adjustedBitmap = Bitmap.createBitmap(newBitmap, 0, 0, newBitmap.getWidth(), newBitmap.getHeight(), matrix, true);
|
||||
}catch (Exception e){
|
||||
adjustedBitmap = newBitmap;
|
||||
}
|
||||
else
|
||||
adjustedBitmap = newBitmap;
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
if( mime.contains("png") || mime.contains(".PNG"))
|
||||
adjustedBitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
|
||||
else
|
||||
adjustedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
|
||||
byte[] bitmapdata = bos.toByteArray();
|
||||
bs = new ByteArrayInputStream(bitmapdata);
|
||||
}else {
|
||||
try {
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(uriFile);
|
||||
byte[] buff = new byte[8 * 1024];
|
||||
int bytesRead;
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
assert inputStream != null;
|
||||
while((bytesRead = inputStream.read(buff)) != -1) {
|
||||
bao.write(buff, 0, bytesRead);
|
||||
}
|
||||
byte[] data = bao.toByteArray();
|
||||
bs = new ByteArrayInputStream(data);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
else
|
||||
adjustedBitmap = newBitmap;
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
if( mime !=null && (mime.contains("png") || mime.contains(".PNG")))
|
||||
adjustedBitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
|
||||
else
|
||||
adjustedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
|
||||
byte[] bitmapdata = bos.toByteArray();
|
||||
bs = new ByteArrayInputStream(bitmapdata);
|
||||
}
|
||||
}else {
|
||||
try {
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(uriFile);
|
||||
|
@ -3286,7 +3313,7 @@ public class Helper {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}else {
|
||||
}else{
|
||||
try {
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(uriFile);
|
||||
byte[] buff = new byte[8 * 1024];
|
||||
|
@ -3304,6 +3331,7 @@ public class Helper {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
|
@ -3440,6 +3468,7 @@ public class Helper {
|
|||
return text.length() - countWithEmoji(text);
|
||||
}
|
||||
|
||||
|
||||
public static int countWithEmoji(String text){
|
||||
int emojiCount = 0;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
|
@ -3856,6 +3885,11 @@ public class Helper {
|
|||
if (dir.isDirectory()) {
|
||||
Helper.deleteDir(dir);
|
||||
}
|
||||
SQLiteDatabase db = Sqlite.getInstance(contextReference.get(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
|
||||
new StatusCacheDAO(contextReference.get(), db).removeDuplicate();
|
||||
Date date = new Date( System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
|
||||
String dateString = Helper.dateToString(date);
|
||||
new TimelineCacheDAO(contextReference.get(), db).removeAfterDate(dateString);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package app.fedilab.android.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Work from: https://github.com/percolate/mentions/blob/master/Mentions/sample/src/main/java/com/percolate/mentions/sample/adapters/RecyclerItemClickListener.java
|
||||
* An onClick listener for items in a RecyclerView. This was taken from the sample provided in the StickyHeadersRecyclerView library.
|
||||
* https://github.com/timehop/sticky-headers-recyclerview/blob/master/sample/src/main/java/com/timehop/stickyheadersrecyclerview/sample/RecyclerItemClickListener.java
|
||||
*/
|
||||
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
|
||||
private final OnItemClickListener mListener;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
|
||||
private final GestureDetector mGestureDetector;
|
||||
|
||||
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
|
||||
mListener = listener;
|
||||
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override public boolean onSingleTapUp(MotionEvent e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(@NotNull RecyclerView view, @NotNull MotionEvent e) {
|
||||
View childView = view.findChildViewUnder(e.getX(), e.getY());
|
||||
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
|
||||
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchEvent(@NotNull RecyclerView view, @NotNull MotionEvent motionEvent) { }
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/* Copyright 2019 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
package app.fedilab.android.interfaces;
|
||||
|
||||
import app.fedilab.android.client.Entities.Status;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Thomas on 19/07/2019.
|
||||
* Interface when retrieving image from img tags
|
||||
*/
|
||||
public interface OnRetrieveImageInterface {
|
||||
void onRetrieveImage(Status status, boolean fromTranslation);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* Copyright 2019 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
package app.fedilab.android.interfaces;
|
||||
|
||||
import app.fedilab.android.client.Entities.Statistics;
|
||||
|
||||
/**
|
||||
* Created by Thomas on 23/07/2019.
|
||||
* Interface when retrieving stats
|
||||
*/
|
||||
public interface OnRetrieveStatsInterface {
|
||||
void onStats(Statistics statistics);
|
||||
}
|
|
@ -23,7 +23,9 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import app.fedilab.android.client.Entities.Statistics;
|
||||
import app.fedilab.android.client.Entities.Status;
|
||||
import app.fedilab.android.helper.FilterToots;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
|
@ -189,6 +191,11 @@ public class StatusCacheDAO {
|
|||
return db.delete(Sqlite.TABLE_STATUSES_CACHE, Sqlite.COL_CACHED_ACTION + " = \""+ cacheType +"\" AND " + Sqlite.COL_STATUS_ID + " = \"" + status.getId() + "\" AND " + Sqlite.COL_INSTANCE + " = \"" + instance + "\" AND " + Sqlite.COL_USER_ID + " = '" + userId+ "'", null);
|
||||
}
|
||||
|
||||
public void removeDuplicate(){
|
||||
db.execSQL("DELETE FROM "+Sqlite.TABLE_STATUSES_CACHE+" WHERE "+Sqlite.COL_ID+" NOT IN (SELECT MIN("+Sqlite.COL_ID+") FROM "+Sqlite.TABLE_STATUSES_CACHE+" GROUP BY "+Sqlite.COL_STATUS_ID+","+Sqlite.COL_INSTANCE+")");
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Remove stored status
|
||||
* @return int
|
||||
|
@ -438,7 +445,117 @@ public class StatusCacheDAO {
|
|||
}
|
||||
}
|
||||
|
||||
public Statistics getStat(){
|
||||
|
||||
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
|
||||
String instance = Helper.getLiveInstance(context);
|
||||
|
||||
Statistics statistics = new Statistics();
|
||||
|
||||
//Count All
|
||||
Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"'"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setTotal_statuses(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
//Count boosts
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_REBLOG + " IS NOT NULL" + " AND " + Sqlite.COL_REBLOG + " != ''"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setNumber_boosts(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
//Count replies
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_IN_REPLY_TO_ID + " IS NOT NULL" + " AND " + Sqlite.COL_IN_REPLY_TO_ID + " != 'null'" + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setNumber_replies(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
statistics.setNumber_status(statistics.getTotal_statuses() - statistics.getNumber_boosts() - statistics.getNumber_replies());
|
||||
|
||||
//Count media
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_MEDIA_ATTACHMENTS + " IS NOT NULL" + " AND " + Sqlite.COL_MEDIA_ATTACHMENTS + " !='"+Helper.attachmentToStringStorage(new ArrayList<>())+"' " + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setNumber_with_media(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
|
||||
//Count sensitive
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_SENSITIVE + "= 1 AND " + Sqlite.COL_MEDIA_ATTACHMENTS + " IS NOT NULL" + " AND " + Sqlite.COL_MEDIA_ATTACHMENTS + " !='"+Helper.attachmentToStringStorage(new ArrayList<>())+"' " + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setNumber_with_sensitive_media(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
|
||||
//Count sensitive
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_SPOILER_TEXT + " IS NOT NULL" + " AND " + Sqlite.COL_SPOILER_TEXT + " != '' " + " AND " +Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setNumber_with_cw(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
//Count public
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_VISIBILITY + "='public'" + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setV_public(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
//Count unlisted
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_VISIBILITY + "='unlisted'" + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setV_unlisted(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
//Count private
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_VISIBILITY + "='private'" + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setV_private(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
|
||||
//Count private
|
||||
mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_STATUSES_CACHE
|
||||
+ " where " + Sqlite.COL_CACHED_ACTION + " = '" + ARCHIVE_CACHE + "' AND " + Sqlite.COL_USER_ID + " = '" + userId + "' AND " + Sqlite.COL_INSTANCE + " = '" + instance +"' AND "
|
||||
+ Sqlite.COL_VISIBILITY + "='direct'" + " AND " + Sqlite.COL_REBLOG + " IS NULL"
|
||||
, null);
|
||||
mCount.moveToFirst();
|
||||
statistics.setV_direct(mCount.getInt(0));
|
||||
mCount.close();
|
||||
|
||||
statistics.setFirstTootDate(getSmallerDate(ARCHIVE_CACHE));
|
||||
statistics.setLastTootDate(getGreaterDate(ARCHIVE_CACHE));
|
||||
|
||||
long diff = statistics.getLastTootDate().getTime() - statistics.getFirstTootDate().getTime();
|
||||
long days = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
|
||||
statistics.setFrequency((float)statistics.getTotal_statuses()/days);
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M3.5,18.49l6,-6.01 4,4L22,6.92l-1.41,-1.41 -7.09,7.97 -4,-4L2,16.99z"/>
|
||||
</vector>
|
|
@ -17,6 +17,8 @@
|
|||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:aztec="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:app="http://schemas.android.com/tools"
|
||||
android:fillViewport="true">
|
||||
|
||||
<RelativeLayout
|
||||
|
@ -49,6 +51,7 @@
|
|||
android:visibility="gone" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/composer_container"
|
||||
android:layout_below="@+id/toot_cw_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -71,6 +74,40 @@
|
|||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:minLines="4" />
|
||||
</ScrollView>
|
||||
|
||||
<HorizontalScrollView android:id="@+id/toolbar"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#e6e6e6"
|
||||
android:scrollbars="none">
|
||||
<include layout="@layout/editor_toolbar_linearlayout_horizontal" />
|
||||
</HorizontalScrollView>
|
||||
<ScrollView
|
||||
android:id="@+id/wysiwyg_container"
|
||||
android:visibility="gone"
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/bottom_bar_tooting"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="0dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:fillViewport="true">
|
||||
<com.github.irshulx.Editor
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/editor"
|
||||
app:render_type="Editor"
|
||||
android:hint="@string/toot_placeholder"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="100dp"
|
||||
/>
|
||||
</ScrollView>
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_bar_tooting"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -27,10 +27,8 @@
|
|||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
app:popupTheme="?attr/popupOverlay"/>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout
|
||||
android:id="@+id/main_app_container"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:paddingLeft="@dimen/fab_margin"
|
||||
android:paddingRight="@dimen/fab_margin"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -82,7 +80,7 @@
|
|||
android:layout_height="match_parent" />
|
||||
</RelativeLayout>
|
||||
<!-- Main Loader -->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:aztec="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:app="http://schemas.android.com/tools"
|
||||
android:fillViewport="true">
|
||||
|
||||
<RelativeLayout
|
||||
|
@ -50,12 +52,12 @@
|
|||
android:visibility="gone" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/composer_container"
|
||||
android:layout_below="@+id/toot_cw_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/bottom_bar_tooting"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="0dp"
|
||||
|
@ -71,6 +73,44 @@
|
|||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:minLines="4" />
|
||||
</ScrollView>
|
||||
<HorizontalScrollView android:id="@+id/toolbar"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#e6e6e6"
|
||||
android:scrollbars="none">
|
||||
<include layout="@layout/editor_toolbar_linearlayout_horizontal" />
|
||||
</HorizontalScrollView>
|
||||
<ScrollView
|
||||
android:id="@+id/wysiwyg_container"
|
||||
android:visibility="gone"
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/bottom_bar_tooting"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="0dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:fillViewport="true">
|
||||
<com.github.irshulx.Editor
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/editor"
|
||||
app:render_type="Editor"
|
||||
android:hint="@string/toot_placeholder"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="100dp"
|
||||
/>
|
||||
</ScrollView>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/suggestions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_bar_tooting"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2019 Thomas Schneider
|
||||
|
||||
This file is a part of Fedilab
|
||||
|
||||
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.
|
||||
|
||||
Fedilab 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 Fedilab; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:id="@+id/suggestion_container"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
<ImageView
|
||||
android:layout_margin="5dp"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/suggestion_image"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:contentDescription="@string/profile_picture" />
|
||||
<TextView
|
||||
android:layout_marginStart="10dp"
|
||||
android:maxLines="1"
|
||||
android:id="@+id/suggestion_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
|
@ -1480,6 +1480,39 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<!-- WYSIWYG -->
|
||||
<LinearLayout
|
||||
android:id="@+id/set_wysiwyg_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_marginTop="@dimen/settings_checkbox_margin"
|
||||
android:layout_marginBottom="@dimen/settings_checkbox_margin"
|
||||
android:orientation="horizontal">
|
||||
<CheckBox
|
||||
android:id="@+id/set_wysiwyg"
|
||||
android:layout_width="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:layout_height="wrap_content" />
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:textSize="16sp"
|
||||
android:text="@string/set_wysiwyg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:textColor="@color/mastodonC2"
|
||||
android:text="@string/set_wysiwyg_indication"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:textSize="16sp"
|
||||
android:id="@+id/set_automatically_split_toot"
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2019 Thomas Schneider
|
||||
|
||||
This file is a part of Fedilab
|
||||
|
||||
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.
|
||||
|
||||
Fedilab 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 Fedilab; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:paddingLeft="@dimen/fab_margin"
|
||||
android:paddingRight="@dimen/fab_margin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ScrollView
|
||||
android:id="@+id/stats_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_vertical_margin"
|
||||
android:paddingEnd="@dimen/activity_vertical_margin"
|
||||
android:paddingRight="@dimen/activity_vertical_margin"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?colorAccent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/date_range"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?colorAccent" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/first_toot_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/first_toot_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/last_toot_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/last_toot_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/frequency"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/frequency"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<!-- STATUSES -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?colorAccent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/statuses"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?colorAccent" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/total_statuses"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/total_statuses"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/number_boosts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/number_boosts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/number_replies"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/number_replies"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/number_statuses"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/number_statuses"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/number_with_media"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/number_with_media"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/number_with_cw"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/number_with_cw"
|
||||
android:textAlignment="textEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/number_with_sensitive_media"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/number_with_sensitive_media"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- VISIBILITY -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:orientation="horizontal">
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?colorAccent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/visibility"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?colorAccent" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/v_public"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/v_public"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/v_unlisted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="textEnd"
|
||||
android:id="@+id/v_unlisted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/v_private"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/v_private"
|
||||
android:textAlignment="textEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_weight="2"
|
||||
android:text="@string/v_direct"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/v_direct"
|
||||
android:textAlignment="textEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
<!-- Main Loader -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
>
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
|
@ -6,6 +6,11 @@
|
|||
android:title="@string/action_sync"
|
||||
android:icon="@drawable/ic_sync"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_stats"
|
||||
android:title="@string/action_stats"
|
||||
android:icon="@drawable/ic_show_stats"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_filter"
|
||||
android:title="@string/action_filter"
|
||||
|
|
|
@ -17,4 +17,5 @@
|
|||
<dimen name="activity_vertical_margin_login">50dp</dimen>
|
||||
<dimen name="badge_count_textsize">12sp</dimen>
|
||||
<dimen name="editor_size">35dp</dimen>
|
||||
<dimen name="format_bar_height">50dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -1120,6 +1120,23 @@
|
|||
<string name="set_enable_crash_report_indication">If enabled, a crash report will be created locally and then you will be able to share it.</string>
|
||||
<string name="crash_title">Fedilab has stopped :(</string>
|
||||
<string name="crash_message">You can send me by email the crash report. It will help to fix it :)\n\nYou can add additional content. Thank you!</string>
|
||||
<string name="set_wysiwyg">Use the wysiwyg</string>
|
||||
<string name="set_wysiwyg_indication">When enabled, you will be able to format your text easily with tools.</string>
|
||||
<string name="action_stats">Statistics</string>
|
||||
<string name="total_statuses">Total statuses</string>
|
||||
<string name="number_boosts">Number of boosts</string>
|
||||
<string name="number_replies">Number of replies</string>
|
||||
<string name="number_statuses">Number of statuses</string>
|
||||
<string name="statuses">Statuses</string>
|
||||
<string name="visibility">Visibility</string>
|
||||
<string name="number_with_media">Number with media</string>
|
||||
<string name="number_with_sensitive_media">Number with sensitive media</string>
|
||||
<string name="number_with_cw">Number with CW</string>
|
||||
<string name="first_toot_date">First status date</string>
|
||||
<string name="last_toot_date">Last status date</string>
|
||||
<string name="frequency">Frequency</string>
|
||||
<string name="toot_per_day">%s statuses per day</string>
|
||||
<string name="date_range">Date range</string>
|
||||
<plurals name="number_of_vote">
|
||||
<item quantity="one">%d vote</item>
|
||||
<item quantity="other">%d votes</item>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme_NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<style name="AppTheme_NoActionBar_Fedilab" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:textColor">@color/light_black</item>
|
||||
<item name="android:scrollbarThumbVertical">@color/transparent</item>
|
||||
<item name="colorPrimary">@color/white</item>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
Added:
|
||||
- Crash reports can be sent by email (default: disabled)
|
||||
|
||||
Changed
|
||||
- User agent reversed to its default value
|
||||
- Decrease the number of accounts/statuses/notifications loaded per page (40 -> 20)
|
||||
|
||||
Fixed
|
||||
- Notification counter issue
|
||||
- Fix boost/reply/fav with the news timeline
|
||||
- Fix some crashes
|
|
@ -1,6 +1,6 @@
|
|||
Nouveautés
|
||||
- Modération et administration de l'instance depuis l'application (doit être activé dans les paramètres)
|
||||
- Support des fichiers audio (téléversement et dans les pouets)
|
||||
- Modération et administration de l’instance depuis l’application (doit être activé dans les paramètres)
|
||||
- Support des fichiers audio dans Mastodon (écoute et transfert)
|
||||
|
||||
Modifié
|
||||
- Suppression du blocage d'instances dans l'application
|
||||
- Suppression de l’option de blocage d’instances dans l’application
|
|
@ -1,17 +1,17 @@
|
|||
Fedilab est un client Android permettant d’accéder au Fediverse
|
||||
Fedilab est un client Android permettant d’accéder au Fédiverse
|
||||
|
||||
Il fonctionne avec:
|
||||
- Mastodon, Pleroma, Peertube, GNU Social, Friendica.
|
||||
Il fonctionne avec :
|
||||
- Mastodon, Pleroma, Peertube, GNU Social et Friendica.
|
||||
|
||||
L'application a des fonctionnalités avancées (Plus particulièrement pour Pleroma et Mastodon):
|
||||
L’application possède des fonctionnalités avancées (plus particulièrement pour Pleroma et Mastodon) :
|
||||
|
||||
- Connexion de plusieurs comptes
|
||||
- Programmation de messages depuis l'application
|
||||
- Programmation de partage
|
||||
- Support multicomptes
|
||||
- Planification de messages depuis l'application
|
||||
- Planification du partage
|
||||
- Utilisation des signets
|
||||
- Suivre et interagir avec des instances
|
||||
- Comptes temporairement mis en sourdine
|
||||
- Suivre et interagir avec des instances distantes
|
||||
- Possibilité de mettre des comptes temporairement en sourdine
|
||||
- Actions entre comptes grâce aux appuis longs
|
||||
- Outils de traduction
|
||||
- Art timelines
|
||||
- Vidéo timelines
|
||||
- Option de traduction
|
||||
- Fils artistiques
|
||||
- Fils vidéos
|
|
@ -1 +1 @@
|
|||
Client multi compte pour le Fediverse
|
||||
Un client multicomptes pour le Fédiverse
|
Loading…
Reference in New Issue