From aa2394748c2d2ff2b0f0b61354a51f15f43c3c8f Mon Sep 17 00:00:00 2001
From: Vavassor
Date: Thu, 4 May 2017 18:55:34 -0400
Subject: [PATCH] Reorganizes the whole codebase.
---
.../keylesspalace/tusky/MessagingService.java | 7 +-
app/src/main/AndroidManifest.xml | 4 +-
.../keylesspalace/tusky/AccountActivity.java | 13 +-
.../tusky/AccountListActivity.java | 2 +
.../com/keylesspalace/tusky/BaseActivity.java | 9 +-
.../keylesspalace/tusky/ComposeActivity.java | 11 +-
.../tusky/EditProfileActivity.java | 3 +-
.../tusky/FavouritesActivity.java | 4 +
.../keylesspalace/tusky/LoginActivity.java | 4 +
.../com/keylesspalace/tusky/MainActivity.java | 7 +-
.../tusky/PreferencesActivity.java | 2 +
.../keylesspalace/tusky/ReportActivity.java | 4 +
.../keylesspalace/tusky/ViewTagActivity.java | 4 +
.../tusky/ViewThreadActivity.java | 4 +
.../tusky/{ => adapter}/AccountAdapter.java | 13 +-
.../tusky/{ => adapter}/BlocksAdapter.java | 8 +-
.../tusky/{ => adapter}/FollowAdapter.java | 8 +-
.../{ => adapter}/FollowRequestsAdapter.java | 8 +-
.../tusky/{ => adapter}/FooterViewHolder.java | 4 +-
.../tusky/{ => adapter}/MutesAdapter.java | 11 +-
.../{ => adapter}/NotificationsAdapter.java | 19 +-
.../tusky/{ => adapter}/ReportAdapter.java | 18 +-
.../tusky/{ => adapter}/StatusViewHolder.java | 14 +-
.../tusky/{ => adapter}/ThreadAdapter.java | 15 +-
.../tusky/{ => adapter}/TimelineAdapter.java | 21 +-
.../keylesspalace/tusky/entity/Account.java | 4 +-
.../{ => fragment}/AccountListFragment.java | 16 +-
.../tusky/{ => fragment}/BaseFragment.java | 4 +-
.../ComposeOptionsFragment.java | 7 +-
.../{ => fragment}/NotificationsFragment.java | 11 +-
.../{ => fragment}/PreferencesFragment.java | 4 +-
.../tusky/{ => fragment}/SFragment.java | 15 +-
.../{ => fragment}/TimelineFragment.java | 12 +-
.../{ => fragment}/ViewMediaFragment.java | 3 +-
.../{ => fragment}/ViewThreadFragment.java | 12 +-
.../AccountActionListener.java | 4 +-
.../{ => interfaces}/AdapterItemRemover.java | 4 +-
.../tusky/{ => interfaces}/LinkListener.java | 4 +-
.../StatusActionListener.java | 4 +-
.../StatusRemoveListener.java | 4 +-
.../tusky/{ => json}/SpannedTypeAdapter.java | 3 +-
.../tusky/{ => json}/StringWithEmoji.java | 2 +-
.../StringWithEmojiTypeAdapter.java | 4 +-
.../tusky/{ => network}/MastodonAPI.java | 2 +-
.../tusky/{ => network}/TuskyAPI.java | 2 +-
.../{ => pager}/AccountPagerAdapter.java | 16 +-
.../{ => pager}/TimelinePagerAdapter.java | 13 +-
.../tusky/{ => service}/TuskyTileService.java | 4 +-
.../com/keylesspalace/tusky/util/Assert.java | 29 +++
.../ConversationLineItemDecoration.java | 8 +-
.../tusky/util/CountUpDownLatch.java | 40 +++
.../tusky/{ => util}/CustomTabURLSpan.java | 4 +-
.../tusky/{ => util}/CustomTabsHelper.java | 2 +-
.../keylesspalace/tusky/util/DateUtils.java | 50 ++++
.../tusky/{ => util}/DownsizeImageTask.java | 8 +-
.../tusky/{ => util}/EditTextTyped.java | 2 +-
.../{ => util}/EndlessOnScrollListener.java | 8 +-
.../tusky/{ => util}/FlowLayout.java | 4 +-
.../keylesspalace/tusky/util/HtmlUtils.java | 54 ++++
.../com/keylesspalace/tusky/util/IOUtils.java | 44 ++++
.../tusky/{ => util}/LinkHelper.java | 14 +-
.../com/keylesspalace/tusky/util/Log.java | 53 ++++
.../NotificationClearBroadcastReceiver.java | 2 +-
.../tusky/{ => util}/NotificationMaker.java | 8 +-
.../keylesspalace/tusky/util/OkHttpUtils.java | 244 ++++++++++++++++++
.../{ => util}/RoundedTransformation.java | 2 +-
.../keylesspalace/tusky/util/SpanUtils.java | 129 +++++++++
.../keylesspalace/tusky/util/ThemeUtils.java | 68 +++++
app/src/main/res/layout/activity_compose.xml | 2 +-
app/src/main/res/layout/item_status.xml | 4 +-
70 files changed, 1012 insertions(+), 138 deletions(-)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/AccountAdapter.java (87%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/BlocksAdapter.java (94%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/FollowAdapter.java (93%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/FollowRequestsAdapter.java (94%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/FooterViewHolder.java (93%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/MutesAdapter.java (93%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/NotificationsAdapter.java (95%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/ReportAdapter.java (90%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/StatusViewHolder.java (96%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/ThreadAdapter.java (88%)
rename app/src/main/java/com/keylesspalace/tusky/{ => adapter}/TimelineAdapter.java (88%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/AccountListFragment.java (95%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/BaseFragment.java (95%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/ComposeOptionsFragment.java (97%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/NotificationsFragment.java (96%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/PreferencesFragment.java (92%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/SFragment.java (95%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/TimelineFragment.java (96%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/ViewMediaFragment.java (99%)
rename app/src/main/java/com/keylesspalace/tusky/{ => fragment}/ViewThreadFragment.java (93%)
rename app/src/main/java/com/keylesspalace/tusky/{ => interfaces}/AccountActionListener.java (92%)
rename app/src/main/java/com/keylesspalace/tusky/{ => interfaces}/AdapterItemRemover.java (89%)
rename app/src/main/java/com/keylesspalace/tusky/{ => interfaces}/LinkListener.java (90%)
rename app/src/main/java/com/keylesspalace/tusky/{ => interfaces}/StatusActionListener.java (91%)
rename app/src/main/java/com/keylesspalace/tusky/{ => interfaces}/StatusRemoveListener.java (89%)
rename app/src/main/java/com/keylesspalace/tusky/{ => json}/SpannedTypeAdapter.java (93%)
rename app/src/main/java/com/keylesspalace/tusky/{ => json}/StringWithEmoji.java (96%)
rename app/src/main/java/com/keylesspalace/tusky/{ => json}/StringWithEmojiTypeAdapter.java (91%)
rename app/src/main/java/com/keylesspalace/tusky/{ => network}/MastodonAPI.java (99%)
rename app/src/main/java/com/keylesspalace/tusky/{ => network}/TuskyAPI.java (96%)
rename app/src/main/java/com/keylesspalace/tusky/{ => pager}/AccountPagerAdapter.java (84%)
rename app/src/main/java/com/keylesspalace/tusky/{ => pager}/TimelinePagerAdapter.java (87%)
rename app/src/main/java/com/keylesspalace/tusky/{ => service}/TuskyTileService.java (94%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/Assert.java
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/ConversationLineItemDecoration.java (89%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/CountUpDownLatch.java
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/CustomTabURLSpan.java (96%)
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/CustomTabsHelper.java (99%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/DateUtils.java
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/DownsizeImageTask.java (97%)
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/EditTextTyped.java (98%)
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/EndlessOnScrollListener.java (90%)
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/FlowLayout.java (98%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/HtmlUtils.java
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/IOUtils.java
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/LinkHelper.java (87%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/Log.java
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/NotificationClearBroadcastReceiver.java (97%)
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/NotificationMaker.java (97%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
rename app/src/main/java/com/keylesspalace/tusky/{ => util}/RoundedTransformation.java (98%)
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/SpanUtils.java
create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java
diff --git a/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java b/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java
index 01d98122d..ca446945d 100644
--- a/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java
+++ b/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java
@@ -21,12 +21,17 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.Spanned;
-import android.util.ArraySet;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.keylesspalace.tusky.entity.Notification;
+import com.keylesspalace.tusky.json.SpannedTypeAdapter;
+import com.keylesspalace.tusky.json.StringWithEmoji;
+import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
+import com.keylesspalace.tusky.network.MastodonAPI;
+import com.keylesspalace.tusky.util.NotificationMaker;
+import com.keylesspalace.tusky.util.OkHttpUtils;
import java.util.HashSet;
import java.util.List;
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a286e60e4..b5724943e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -79,11 +79,11 @@
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />
-
+
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java
index ed12bd2cb..f3a83f4d0 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java
@@ -23,6 +23,7 @@ import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.support.annotation.AttrRes;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
@@ -43,6 +44,14 @@ import android.widget.TextView;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Relationship;
+import com.keylesspalace.tusky.fragment.SFragment;
+import com.keylesspalace.tusky.interfaces.LinkListener;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+import com.keylesspalace.tusky.pager.AccountPagerAdapter;
+import com.keylesspalace.tusky.util.LinkHelper;
+import com.keylesspalace.tusky.util.Assert;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import com.pkmmte.view.CircularImageView;
import com.squareup.picasso.Picasso;
@@ -237,7 +246,9 @@ public class AccountActivity extends BaseActivity implements SFragment.OnUserRem
displayName.setText(account.getDisplayName());
- LinkHelper.setClickableText(note, account.note, null, new LinkListener() {
+ boolean useCustomTabs = PreferenceManager.getDefaultSharedPreferences(this)
+ .getBoolean("customTabs", true);
+ LinkHelper.setClickableText(note, account.note, null, useCustomTabs, new LinkListener() {
@Override
public void onViewTag(String tag) {
Intent intent = new Intent(AccountActivity.this, ViewTagActivity.class);
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.java b/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.java
index 1d1276fbc..86c5a05c3 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.java
@@ -24,6 +24,8 @@ import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
+import com.keylesspalace.tusky.fragment.AccountListFragment;
+
public class AccountListActivity extends BaseActivity {
enum Type {
BLOCKS,
diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
index 5bbe7ba13..1803cacd1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
@@ -34,6 +34,13 @@ import android.view.Menu;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+import com.keylesspalace.tusky.json.SpannedTypeAdapter;
+import com.keylesspalace.tusky.json.StringWithEmoji;
+import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
+import com.keylesspalace.tusky.network.MastodonAPI;
+import com.keylesspalace.tusky.network.TuskyAPI;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.OkHttpUtils;
import java.io.IOException;
@@ -51,7 +58,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class BaseActivity extends AppCompatActivity {
private static final String TAG = "BaseActivity"; // logging tag
- protected MastodonAPI mastodonAPI;
+ public MastodonAPI mastodonAPI;
protected TuskyAPI tuskyAPI;
protected Dispatcher mastodonApiDispatcher;
protected PendingIntent serviceAlarmIntent;
diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java
index 15fefa90d..f0089fd2f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java
@@ -71,6 +71,14 @@ import android.widget.TextView;
import com.keylesspalace.tusky.entity.Media;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.fragment.ComposeOptionsFragment;
+import com.keylesspalace.tusky.util.DownsizeImageTask;
+import com.keylesspalace.tusky.util.EditTextTyped;
+import com.keylesspalace.tusky.util.CountUpDownLatch;
+import com.keylesspalace.tusky.util.IOUtils;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.SpanUtils;
+import com.keylesspalace.tusky.util.ThemeUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -119,7 +127,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private Uri photoUploadUri;
// this only exists when a status is trying to be sent, but uploads are still occurring
private ProgressDialog finishingUploadDialog;
- @BindView(R.id.compose_edit_field) EditTextTyped textEditor;
+ @BindView(R.id.compose_edit_field)
+ EditTextTyped textEditor;
@BindView(R.id.compose_media_preview_bar) LinearLayout mediaPreviewBar;
@BindView(R.id.compose_content_warning_bar) View contentWarningBar;
@BindView(R.id.field_content_warning) EditText contentWarningEditor;
diff --git a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.java b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.java
index ddb538083..23c633b63 100644
--- a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.java
@@ -36,7 +36,6 @@ import android.util.Base64;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
@@ -44,6 +43,8 @@ import android.widget.ProgressBar;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Profile;
+import com.keylesspalace.tusky.util.IOUtils;
+import com.keylesspalace.tusky.util.Log;
import com.pkmmte.view.CircularImageView;
import com.squareup.picasso.Picasso;
import com.theartofdev.edmodo.cropper.CropImage;
diff --git a/app/src/main/java/com/keylesspalace/tusky/FavouritesActivity.java b/app/src/main/java/com/keylesspalace/tusky/FavouritesActivity.java
index f45ab2c6c..7755f2177 100644
--- a/app/src/main/java/com/keylesspalace/tusky/FavouritesActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/FavouritesActivity.java
@@ -23,6 +23,10 @@ import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
+import com.keylesspalace.tusky.fragment.SFragment;
+import com.keylesspalace.tusky.fragment.TimelineFragment;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+
public class FavouritesActivity extends BaseActivity implements SFragment.OnUserRemovedListener {
private StatusRemoveListener statusRemoveListener;
diff --git a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java
index b85f1faaa..8ec477484 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java
@@ -36,6 +36,10 @@ import android.widget.TextView;
import com.keylesspalace.tusky.entity.AccessToken;
import com.keylesspalace.tusky.entity.AppCredentials;
+import com.keylesspalace.tusky.network.MastodonAPI;
+import com.keylesspalace.tusky.util.CustomTabsHelper;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.OkHttpUtils;
import java.util.HashMap;
import java.util.Map;
diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
index 764d1bddf..c93bb5ed6 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
@@ -42,6 +42,11 @@ import com.arlib.floatingsearchview.FloatingSearchView;
import com.arlib.floatingsearchview.suggestions.SearchSuggestionsAdapter;
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion;
import com.keylesspalace.tusky.entity.Account;
+import com.keylesspalace.tusky.fragment.SFragment;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+import com.keylesspalace.tusky.pager.TimelinePagerAdapter;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
@@ -82,7 +87,7 @@ public class MainActivity extends BaseActivity implements SFragment.OnUserRemove
@BindView(R.id.tab_layout) TabLayout tabLayout;
@BindView(R.id.pager) ViewPager viewPager;
- FloatingActionButton composeButton;
+ public FloatingActionButton composeButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java
index 53e4f22a4..58c185881 100644
--- a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java
@@ -21,6 +21,8 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
+import com.keylesspalace.tusky.fragment.PreferencesFragment;
+
public class PreferencesActivity extends BaseActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
private boolean themeSwitched;
diff --git a/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java b/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java
index 0c3d1895f..f8e4e4472 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java
@@ -30,7 +30,11 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
+import com.keylesspalace.tusky.adapter.ReportAdapter;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.util.HtmlUtils;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java b/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java
index 9bce54a14..e73d490a2 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java
@@ -23,6 +23,10 @@ import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
+import com.keylesspalace.tusky.fragment.SFragment;
+import com.keylesspalace.tusky.fragment.TimelineFragment;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+
import butterknife.BindView;
import butterknife.ButterKnife;
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewThreadActivity.java b/app/src/main/java/com/keylesspalace/tusky/ViewThreadActivity.java
index 160e438f6..20b3534ac 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewThreadActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/ViewThreadActivity.java
@@ -25,6 +25,10 @@ import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
+import com.keylesspalace.tusky.fragment.SFragment;
+import com.keylesspalace.tusky.fragment.ViewThreadFragment;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+
public class ViewThreadActivity extends BaseActivity implements SFragment.OnUserRemovedListener {
Fragment viewThreadFragment;
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.java
similarity index 87%
rename from app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.java
index 9941d34d3..48c6634bf 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.java
@@ -13,17 +13,18 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import com.keylesspalace.tusky.entity.Account;
+import com.keylesspalace.tusky.interfaces.AccountActionListener;
import java.util.ArrayList;
import java.util.List;
-abstract class AccountAdapter extends RecyclerView.Adapter {
+public abstract class AccountAdapter extends RecyclerView.Adapter {
List accountList;
AccountActionListener accountActionListener;
@@ -38,7 +39,7 @@ abstract class AccountAdapter extends RecyclerView.Adapter {
return accountList.size() + 1;
}
- void update(List newAccounts) {
+ public void update(List newAccounts) {
if (newAccounts == null || newAccounts.isEmpty()) {
return;
}
@@ -59,14 +60,14 @@ abstract class AccountAdapter extends RecyclerView.Adapter {
notifyDataSetChanged();
}
- void addItems(List newAccounts) {
+ public void addItems(List newAccounts) {
int end = accountList.size();
accountList.addAll(newAccounts);
notifyItemRangeInserted(end, newAccounts.size());
}
@Nullable
- Account removeItem(int position) {
+ public Account removeItem(int position) {
if (position < 0 || position >= accountList.size()) {
return null;
}
@@ -75,7 +76,7 @@ abstract class AccountAdapter extends RecyclerView.Adapter {
return account;
}
- void addItem(Account account, int position) {
+ public void addItem(Account account, int position) {
if (position < 0 || position > accountList.size()) {
return;
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
similarity index 94%
rename from app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
index d052db34b..e4e34fa9b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -22,18 +22,20 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
+import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.pkmmte.view.CircularImageView;
import com.squareup.picasso.Picasso;
import butterknife.BindView;
import butterknife.ButterKnife;
-class BlocksAdapter extends AccountAdapter {
+public class BlocksAdapter extends AccountAdapter {
private static final int VIEW_TYPE_BLOCKED_USER = 0;
private static final int VIEW_TYPE_FOOTER = 1;
- BlocksAdapter(AccountActionListener accountActionListener) {
+ public BlocksAdapter(AccountActionListener accountActionListener) {
super(accountActionListener);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowAdapter.java
similarity index 93%
rename from app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/FollowAdapter.java
index 3b09de247..7e9b825fa 100644
--- a/app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
@@ -22,16 +22,18 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
+import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.pkmmte.view.CircularImageView;
import com.squareup.picasso.Picasso;
/** Both for follows and following lists. */
-class FollowAdapter extends AccountAdapter {
+public class FollowAdapter extends AccountAdapter {
private static final int VIEW_TYPE_ACCOUNT = 0;
private static final int VIEW_TYPE_FOOTER = 1;
- FollowAdapter(AccountActionListener accountActionListener) {
+ public FollowAdapter(AccountActionListener accountActionListener) {
super(accountActionListener);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/FollowRequestsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java
similarity index 94%
rename from app/src/main/java/com/keylesspalace/tusky/FollowRequestsAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java
index 0a54b558b..392d33ac7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/FollowRequestsAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -22,6 +22,8 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
+import com.keylesspalace.tusky.interfaces.AccountActionListener;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
import com.pkmmte.view.CircularImageView;
import com.squareup.picasso.Picasso;
@@ -29,11 +31,11 @@ import com.squareup.picasso.Picasso;
import butterknife.BindView;
import butterknife.ButterKnife;
-class FollowRequestsAdapter extends AccountAdapter {
+public class FollowRequestsAdapter extends AccountAdapter {
private static final int VIEW_TYPE_FOLLOW_REQUEST = 0;
private static final int VIEW_TYPE_FOOTER = 1;
- FollowRequestsAdapter(AccountActionListener accountActionListener) {
+ public FollowRequestsAdapter(AccountActionListener accountActionListener) {
super(accountActionListener);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java
similarity index 93%
rename from app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java
index e39ca44af..5ff1187e7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java
@@ -13,12 +13,14 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ProgressBar;
+import com.keylesspalace.tusky.R;
+
class FooterViewHolder extends RecyclerView.ViewHolder {
FooterViewHolder(View itemView) {
super(itemView);
diff --git a/app/src/main/java/com/keylesspalace/tusky/MutesAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
similarity index 93%
rename from app/src/main/java/com/keylesspalace/tusky/MutesAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
index 2513cac6b..06258a4bc 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MutesAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
@@ -1,4 +1,4 @@
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -7,21 +7,20 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
+import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.pkmmte.view.CircularImageView;
import com.squareup.picasso.Picasso;
-import java.util.HashSet;
-import java.util.Set;
-
import butterknife.BindView;
import butterknife.ButterKnife;
-class MutesAdapter extends AccountAdapter {
+public class MutesAdapter extends AccountAdapter {
private static final int VIEW_TYPE_MUTED_USER = 0;
private static final int VIEW_TYPE_FOOTER = 1;
- MutesAdapter(AccountActionListener accountActionListener) {
+ public MutesAdapter(AccountActionListener accountActionListener) {
super(accountActionListener);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
similarity index 95%
rename from app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
index 2376469b5..639bfea37 100644
--- a/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.content.Context;
import android.graphics.Typeface;
@@ -29,21 +29,24 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Notification;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.interfaces.AdapterItemRemover;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
+public class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
private static final int VIEW_TYPE_MENTION = 0;
private static final int VIEW_TYPE_FOOTER = 1;
private static final int VIEW_TYPE_STATUS_NOTIFICATION = 2;
private static final int VIEW_TYPE_FOLLOW = 3;
- enum FooterState {
+ public enum FooterState {
EMPTY,
END,
LOADING
@@ -54,7 +57,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
private NotificationActionListener notificationActionListener;
private FooterState footerState = FooterState.END;
- NotificationsAdapter(StatusActionListener statusListener,
+ public NotificationsAdapter(StatusActionListener statusListener,
NotificationActionListener notificationActionListener) {
super();
notifications = new ArrayList<>();
@@ -63,7 +66,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
}
- void setFooterState(FooterState newFooterState) {
+ public void setFooterState(FooterState newFooterState) {
FooterState oldValue = footerState;
footerState = newFooterState;
if (footerState != oldValue) {
@@ -179,7 +182,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
return null;
}
- void update(List newNotifications) {
+ public void update(List newNotifications) {
if (newNotifications == null || newNotifications.isEmpty()) {
return;
}
@@ -200,7 +203,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
notifyDataSetChanged();
}
- void addItems(List new_notifications) {
+ public void addItems(List new_notifications) {
int end = notifications.size();
notifications.addAll(new_notifications);
notifyItemRangeInserted(end, new_notifications.size());
@@ -223,7 +226,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
}
}
- interface NotificationActionListener {
+ public interface NotificationActionListener {
void onViewAccount(String id);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/ReportAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/ReportAdapter.java
similarity index 90%
rename from app/src/main/java/com/keylesspalace/tusky/ReportAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/ReportAdapter.java
index ccdf7aa9b..50e07369d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ReportAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/ReportAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.v7.widget.RecyclerView;
import android.text.Spanned;
@@ -24,16 +24,18 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
+import com.keylesspalace.tusky.R;
+
import java.util.ArrayList;
import java.util.List;
-class ReportAdapter extends RecyclerView.Adapter {
- static class ReportStatus {
+public class ReportAdapter extends RecyclerView.Adapter {
+ public static class ReportStatus {
String id;
Spanned content;
boolean checked;
- ReportStatus(String id, Spanned content, boolean checked) {
+ public ReportStatus(String id, Spanned content, boolean checked) {
this.id = id;
this.content = content;
this.checked = checked;
@@ -58,7 +60,7 @@ class ReportAdapter extends RecyclerView.Adapter {
private List statusList;
- ReportAdapter() {
+ public ReportAdapter() {
super();
statusList = new ArrayList<>();
}
@@ -82,13 +84,13 @@ class ReportAdapter extends RecyclerView.Adapter {
return statusList.size();
}
- void addItem(ReportStatus status) {
+ public void addItem(ReportStatus status) {
int end = statusList.size();
statusList.add(status);
notifyItemInserted(end);
}
- void addItems(List newStatuses) {
+ public void addItems(List newStatuses) {
int end = statusList.size();
int added = 0;
for (ReportStatus status : newStatuses) {
@@ -102,7 +104,7 @@ class ReportAdapter extends RecyclerView.Adapter {
}
}
- String[] getCheckedStatusIds() {
+ public String[] getCheckedStatusIds() {
List idList = new ArrayList<>();
for (ReportStatus status : statusList) {
if (status.checked) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
similarity index 96%
rename from app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
index 6a2e431df..1459dd4e0 100644
--- a/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
@@ -13,9 +13,10 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.content.Context;
+import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.text.Spanned;
@@ -26,7 +27,13 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ToggleButton;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.util.RoundedTransformation;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.util.DateUtils;
+import com.keylesspalace.tusky.util.LinkHelper;
+import com.keylesspalace.tusky.util.ThemeUtils;
import com.squareup.picasso.Picasso;
import com.varunest.sparkbutton.SparkButton;
import com.varunest.sparkbutton.SparkEventListener;
@@ -100,7 +107,10 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
StatusActionListener listener) {
/* Redirect URLSpan's in the status content to the listener for viewing tag pages and
* account pages. */
- LinkHelper.setClickableText(this.content, content, mentions, listener);
+ Context context = this.content.getContext();
+ boolean useCustomTabs = PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean("useCustomTabs", true);
+ LinkHelper.setClickableText(this.content, content, mentions, useCustomTabs, listener);
}
private void setAvatar(String url) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/ThreadAdapter.java
similarity index 88%
rename from app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/ThreadAdapter.java
index 97dfc941c..46523f527 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/ThreadAdapter.java
@@ -13,24 +13,27 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.interfaces.AdapterItemRemover;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.entity.Status;
import java.util.ArrayList;
import java.util.List;
-class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
+public class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
private List statuses;
private StatusActionListener statusActionListener;
private int statusIndex;
- ThreadAdapter(StatusActionListener listener) {
+ public ThreadAdapter(StatusActionListener listener) {
this.statusActionListener = listener;
this.statuses = new ArrayList<>();
this.statusIndex = 0;
@@ -55,7 +58,7 @@ class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
return statuses.size();
}
- Status getItem(int position) {
+ public Status getItem(int position) {
return statuses.get(position);
}
@@ -76,7 +79,7 @@ class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
}
}
- int setStatus(Status status) {
+ public int setStatus(Status status) {
if (statuses.size() > 0 && statuses.get(statusIndex).equals(status)) {
// Do not add this status on refresh, it's already in there.
statuses.set(statusIndex, status);
@@ -88,7 +91,7 @@ class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
return i;
}
- void setContext(List ancestors, List descendants) {
+ public void setContext(List ancestors, List descendants) {
Status mainStatus = null;
// In case of refresh, remove old ancestors and descendants first. We'll remove all blindly,
diff --git a/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java
similarity index 88%
rename from app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java
index 759a23579..892197b77 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.adapter;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
@@ -21,16 +21,19 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.interfaces.AdapterItemRemover;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.entity.Status;
import java.util.ArrayList;
import java.util.List;
-class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
+public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
private static final int VIEW_TYPE_STATUS = 0;
private static final int VIEW_TYPE_FOOTER = 1;
- enum FooterState {
+ public enum FooterState {
EMPTY,
END,
LOADING
@@ -40,7 +43,7 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
private StatusActionListener statusListener;
private FooterState footerState = FooterState.END;
- TimelineAdapter(StatusActionListener statusListener) {
+ public TimelineAdapter(StatusActionListener statusListener) {
super();
statuses = new ArrayList<>();
this.statusListener = statusListener;
@@ -79,7 +82,7 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
}
}
- void setFooterState(FooterState newFooterState) {
+ public void setFooterState(FooterState newFooterState) {
FooterState oldValue = footerState;
footerState = newFooterState;
if (footerState != oldValue) {
@@ -110,7 +113,7 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
}
}
- void update(List newStatuses) {
+ public void update(List newStatuses) {
if (newStatuses == null || newStatuses.isEmpty()) {
return;
}
@@ -131,7 +134,7 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
notifyDataSetChanged();
}
- void addItems(List newStatuses) {
+ public void addItems(List newStatuses) {
int end = statuses.size();
statuses.addAll(newStatuses);
notifyItemRangeInserted(end, newStatuses.size());
@@ -142,7 +145,7 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
notifyItemRemoved(position);
}
- void removeAllByAccountId(String accountId) {
+ public void removeAllByAccountId(String accountId) {
for (int i = 0; i < statuses.size();) {
Status status = statuses.get(i);
if (accountId.equals(status.account.id)) {
@@ -155,7 +158,7 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
}
@Nullable
- Status getItem(int position) {
+ public Status getItem(int position) {
if (position >= 0 && position < statuses.size()) {
return statuses.get(position);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Account.java b/app/src/main/java/com/keylesspalace/tusky/entity/Account.java
index e7be8e810..c802bd4aa 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Account.java
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Account.java
@@ -20,8 +20,8 @@ import android.text.Spanned;
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion;
import com.google.gson.annotations.SerializedName;
-import com.keylesspalace.tusky.HtmlUtils;
-import com.keylesspalace.tusky.StringWithEmoji;
+import com.keylesspalace.tusky.util.HtmlUtils;
+import com.keylesspalace.tusky.json.StringWithEmoji;
public class Account implements SearchSuggestion {
public String id;
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountListFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java
similarity index 95%
rename from app/src/main/java/com/keylesspalace/tusky/AccountListFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java
index 1128602f8..df2f57034 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountListFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.content.Intent;
@@ -29,8 +29,22 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
+import com.keylesspalace.tusky.AccountActivity;
+import com.keylesspalace.tusky.adapter.AccountAdapter;
+import com.keylesspalace.tusky.adapter.BlocksAdapter;
+import com.keylesspalace.tusky.adapter.FollowAdapter;
+import com.keylesspalace.tusky.adapter.FollowRequestsAdapter;
+import com.keylesspalace.tusky.adapter.MutesAdapter;
+import com.keylesspalace.tusky.BaseActivity;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Relationship;
+import com.keylesspalace.tusky.interfaces.AccountActionListener;
+import com.keylesspalace.tusky.network.MastodonAPI;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.util.EndlessOnScrollListener;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import java.util.List;
diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/BaseFragment.java
similarity index 95%
rename from app/src/main/java/com/keylesspalace/tusky/BaseFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/BaseFragment.java
index 0a9dcbcf3..c0305d125 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/BaseFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.content.SharedPreferences;
@@ -21,6 +21,8 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
+import com.keylesspalace.tusky.R;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeOptionsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ComposeOptionsFragment.java
similarity index 97%
rename from app/src/main/java/com/keylesspalace/tusky/ComposeOptionsFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/ComposeOptionsFragment.java
index 1b24c27ee..ab5226020 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ComposeOptionsFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ComposeOptionsFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -33,8 +33,11 @@ import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.util.ThemeUtils;
+
public class ComposeOptionsFragment extends BottomSheetDialogFragment {
- interface Listener {
+ public interface Listener {
void onVisibilityChanged(String visibility);
void onContentWarningChanged(boolean hideText);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java
similarity index 96%
rename from app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java
index 56afc0fd8..bef04290d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.content.SharedPreferences;
@@ -31,8 +31,17 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
+import com.keylesspalace.tusky.MainActivity;
+import com.keylesspalace.tusky.adapter.NotificationsAdapter;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Notification;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+import com.keylesspalace.tusky.util.EndlessOnScrollListener;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import java.util.List;
diff --git a/app/src/main/java/com/keylesspalace/tusky/PreferencesFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java
similarity index 92%
rename from app/src/main/java/com/keylesspalace/tusky/PreferencesFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java
index 8820f5eb0..280098a76 100644
--- a/app/src/main/java/com/keylesspalace/tusky/PreferencesFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java
@@ -13,11 +13,13 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.os.Bundle;
import android.preference.PreferenceFragment;
+import com.keylesspalace.tusky.R;
+
public class PreferencesFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/SFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
similarity index 95%
rename from app/src/main/java/com/keylesspalace/tusky/SFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
index 3af5cce0c..71b044261 100644
--- a/app/src/main/java/com/keylesspalace/tusky/SFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -27,8 +27,19 @@ import android.text.Spanned;
import android.view.MenuItem;
import android.view.View;
+import com.keylesspalace.tusky.AccountActivity;
+import com.keylesspalace.tusky.BaseActivity;
+import com.keylesspalace.tusky.ComposeActivity;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.ReportActivity;
+import com.keylesspalace.tusky.ViewTagActivity;
+import com.keylesspalace.tusky.ViewThreadActivity;
+import com.keylesspalace.tusky.ViewVideoActivity;
import com.keylesspalace.tusky.entity.Relationship;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.interfaces.AdapterItemRemover;
+import com.keylesspalace.tusky.network.MastodonAPI;
+import com.keylesspalace.tusky.util.HtmlUtils;
import java.util.ArrayList;
import java.util.List;
@@ -45,7 +56,7 @@ import retrofit2.Response;
* overlap functionality. So, I'm momentarily leaving it and hopefully working on those will clear
* up what needs to be where. */
public abstract class SFragment extends BaseFragment {
- interface OnUserRemovedListener {
+ public interface OnUserRemovedListener {
void onUserRemoved(String accountId);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java
similarity index 96%
rename from app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java
index d23bbed3a..4353c43fe 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.content.SharedPreferences;
@@ -31,7 +31,15 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.keylesspalace.tusky.MainActivity;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.adapter.TimelineAdapter;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+import com.keylesspalace.tusky.util.EndlessOnScrollListener;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import java.util.List;
@@ -47,7 +55,7 @@ public class TimelineFragment extends SFragment implements
private Call> listCall;
- enum Kind {
+ public enum Kind {
HOME,
PUBLIC_LOCAL,
PUBLIC_FEDERATED,
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewMediaFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.java
similarity index 99%
rename from app/src/main/java/com/keylesspalace/tusky/ViewMediaFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.java
index fed8cbebd..9a5dbee23 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewMediaFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.app.AlertDialog;
import android.app.DownloadManager;
@@ -36,6 +36,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import com.keylesspalace.tusky.R;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewThreadFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java
similarity index 93%
rename from app/src/main/java/com/keylesspalace/tusky/ViewThreadFragment.java
rename to app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java
index ef1fc0a74..d02f43596 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewThreadFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -29,8 +29,18 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
+import com.keylesspalace.tusky.adapter.ThreadAdapter;
+import com.keylesspalace.tusky.BaseActivity;
import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.entity.StatusContext;
+import com.keylesspalace.tusky.network.MastodonAPI;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.interfaces.StatusActionListener;
+import com.keylesspalace.tusky.interfaces.StatusRemoveListener;
+import com.keylesspalace.tusky.util.ConversationLineItemDecoration;
+import com.keylesspalace.tusky.util.Log;
+import com.keylesspalace.tusky.util.ThemeUtils;
import retrofit2.Call;
import retrofit2.Callback;
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActionListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java
similarity index 92%
rename from app/src/main/java/com/keylesspalace/tusky/AccountActionListener.java
rename to app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java
index bca609cdf..116bcae8f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountActionListener.java
+++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java
@@ -13,9 +13,9 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.interfaces;
-interface AccountActionListener {
+public interface AccountActionListener {
void onViewAccount(String id);
void onMute(final boolean mute, final String id, final int position);
void onBlock(final boolean block, final String id, final int position);
diff --git a/app/src/main/java/com/keylesspalace/tusky/AdapterItemRemover.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/AdapterItemRemover.java
similarity index 89%
rename from app/src/main/java/com/keylesspalace/tusky/AdapterItemRemover.java
rename to app/src/main/java/com/keylesspalace/tusky/interfaces/AdapterItemRemover.java
index 634935ffa..5b49cbfa7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AdapterItemRemover.java
+++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/AdapterItemRemover.java
@@ -13,8 +13,8 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.interfaces;
-interface AdapterItemRemover {
+public interface AdapterItemRemover {
void removeItem(int position);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/LinkListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/LinkListener.java
similarity index 90%
rename from app/src/main/java/com/keylesspalace/tusky/LinkListener.java
rename to app/src/main/java/com/keylesspalace/tusky/interfaces/LinkListener.java
index 9e188ae42..62360e34a 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LinkListener.java
+++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/LinkListener.java
@@ -13,9 +13,9 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.interfaces;
-interface LinkListener {
+public interface LinkListener {
void onViewTag(String tag);
void onViewAccount(String id);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/StatusActionListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java
similarity index 91%
rename from app/src/main/java/com/keylesspalace/tusky/StatusActionListener.java
rename to app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java
index 1004bb824..b6b80f723 100644
--- a/app/src/main/java/com/keylesspalace/tusky/StatusActionListener.java
+++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java
@@ -13,13 +13,13 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.interfaces;
import android.view.View;
import com.keylesspalace.tusky.entity.Status;
-interface StatusActionListener extends LinkListener {
+public interface StatusActionListener extends LinkListener {
void onReply(int position);
void onReblog(final boolean reblog, final int position);
void onFavourite(final boolean favourite, final int position);
diff --git a/app/src/main/java/com/keylesspalace/tusky/StatusRemoveListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusRemoveListener.java
similarity index 89%
rename from app/src/main/java/com/keylesspalace/tusky/StatusRemoveListener.java
rename to app/src/main/java/com/keylesspalace/tusky/interfaces/StatusRemoveListener.java
index 23111c6ab..c05f76573 100644
--- a/app/src/main/java/com/keylesspalace/tusky/StatusRemoveListener.java
+++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusRemoveListener.java
@@ -13,8 +13,8 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.interfaces;
-interface StatusRemoveListener {
+public interface StatusRemoveListener {
void removePostsByUser(String accountId);
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/SpannedTypeAdapter.java b/app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.java
similarity index 93%
rename from app/src/main/java/com/keylesspalace/tusky/SpannedTypeAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.java
index 3b47acc3b..305adba41 100644
--- a/app/src/main/java/com/keylesspalace/tusky/SpannedTypeAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.json;
import android.text.Spanned;
@@ -22,6 +22,7 @@ import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
+import com.keylesspalace.tusky.util.HtmlUtils;
import java.lang.reflect.Type;
diff --git a/app/src/main/java/com/keylesspalace/tusky/StringWithEmoji.java b/app/src/main/java/com/keylesspalace/tusky/json/StringWithEmoji.java
similarity index 96%
rename from app/src/main/java/com/keylesspalace/tusky/StringWithEmoji.java
rename to app/src/main/java/com/keylesspalace/tusky/json/StringWithEmoji.java
index cad8e8c08..d229c5a99 100644
--- a/app/src/main/java/com/keylesspalace/tusky/StringWithEmoji.java
+++ b/app/src/main/java/com/keylesspalace/tusky/json/StringWithEmoji.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.json;
/**
* This is just a wrapper class for a String.
diff --git a/app/src/main/java/com/keylesspalace/tusky/StringWithEmojiTypeAdapter.java b/app/src/main/java/com/keylesspalace/tusky/json/StringWithEmojiTypeAdapter.java
similarity index 91%
rename from app/src/main/java/com/keylesspalace/tusky/StringWithEmojiTypeAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/json/StringWithEmojiTypeAdapter.java
index ecf18bcd9..86bd2c61b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/StringWithEmojiTypeAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/json/StringWithEmojiTypeAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.json;
import com.emojione.Emojione;
import com.google.gson.JsonDeserializationContext;
@@ -24,7 +24,7 @@ import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
/** This is a type-based workaround to allow for shortcode conversion when loading display names. */
-class StringWithEmojiTypeAdapter implements JsonDeserializer {
+public class StringWithEmojiTypeAdapter implements JsonDeserializer {
@Override
public StringWithEmoji deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
diff --git a/app/src/main/java/com/keylesspalace/tusky/MastodonAPI.java b/app/src/main/java/com/keylesspalace/tusky/network/MastodonAPI.java
similarity index 99%
rename from app/src/main/java/com/keylesspalace/tusky/MastodonAPI.java
rename to app/src/main/java/com/keylesspalace/tusky/network/MastodonAPI.java
index 011fbc40a..aad04523c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MastodonAPI.java
+++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonAPI.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.network;
import com.keylesspalace.tusky.entity.AccessToken;
import com.keylesspalace.tusky.entity.Account;
diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyAPI.java b/app/src/main/java/com/keylesspalace/tusky/network/TuskyAPI.java
similarity index 96%
rename from app/src/main/java/com/keylesspalace/tusky/TuskyAPI.java
rename to app/src/main/java/com/keylesspalace/tusky/network/TuskyAPI.java
index 4831949bd..700de83c8 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TuskyAPI.java
+++ b/app/src/main/java/com/keylesspalace/tusky/network/TuskyAPI.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.network;
import okhttp3.ResponseBody;
import retrofit2.Call;
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountPagerAdapter.java b/app/src/main/java/com/keylesspalace/tusky/pager/AccountPagerAdapter.java
similarity index 84%
rename from app/src/main/java/com/keylesspalace/tusky/AccountPagerAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/pager/AccountPagerAdapter.java
index 505d89bd2..8f04ae186 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountPagerAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/pager/AccountPagerAdapter.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.pager;
import android.content.Context;
import android.support.v4.app.Fragment;
@@ -24,23 +24,27 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.fragment.AccountListFragment;
+import com.keylesspalace.tusky.fragment.TimelineFragment;
+
import java.util.ArrayList;
import java.util.List;
-class AccountPagerAdapter extends FragmentPagerAdapter {
+public class AccountPagerAdapter extends FragmentPagerAdapter {
private Context context;
private String accountId;
private String[] pageTitles;
private List registeredFragments;
- AccountPagerAdapter(FragmentManager manager, Context context, String accountId) {
+ public AccountPagerAdapter(FragmentManager manager, Context context, String accountId) {
super(manager);
this.context = context;
this.accountId = accountId;
registeredFragments = new ArrayList<>();
}
- void setPageTitles(String[] titles) {
+ public void setPageTitles(String[] titles) {
pageTitles = titles;
}
@@ -72,7 +76,7 @@ class AccountPagerAdapter extends FragmentPagerAdapter {
return pageTitles[position];
}
- View getTabView(int position, ViewGroup root) {
+ public View getTabView(int position, ViewGroup root) {
View view = LayoutInflater.from(context).inflate(R.layout.tab_account, root, false);
TextView title = (TextView) view.findViewById(R.id.title);
title.setText(pageTitles[position]);
@@ -92,7 +96,7 @@ class AccountPagerAdapter extends FragmentPagerAdapter {
super.destroyItem(container, position, object);
}
- List getRegisteredFragments() {
+ public List getRegisteredFragments() {
return registeredFragments;
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/TimelinePagerAdapter.java b/app/src/main/java/com/keylesspalace/tusky/pager/TimelinePagerAdapter.java
similarity index 87%
rename from app/src/main/java/com/keylesspalace/tusky/TimelinePagerAdapter.java
rename to app/src/main/java/com/keylesspalace/tusky/pager/TimelinePagerAdapter.java
index 03dc88dc9..826860413 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TimelinePagerAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/pager/TimelinePagerAdapter.java
@@ -13,31 +13,34 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.pager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.ViewGroup;
+import com.keylesspalace.tusky.fragment.NotificationsFragment;
+import com.keylesspalace.tusky.fragment.TimelineFragment;
+
import java.util.ArrayList;
import java.util.List;
-class TimelinePagerAdapter extends FragmentPagerAdapter {
+public class TimelinePagerAdapter extends FragmentPagerAdapter {
private int currentFragmentIndex;
private List registeredFragments;
- TimelinePagerAdapter(FragmentManager manager) {
+ public TimelinePagerAdapter(FragmentManager manager) {
super(manager);
currentFragmentIndex = 0;
registeredFragments = new ArrayList<>();
}
- Fragment getCurrentFragment() {
+ public Fragment getCurrentFragment() {
return registeredFragments.get(currentFragmentIndex);
}
- List getRegisteredFragments() {
+ public List getRegisteredFragments() {
return registeredFragments;
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyTileService.java b/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java
similarity index 94%
rename from app/src/main/java/com/keylesspalace/tusky/TuskyTileService.java
rename to app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java
index 720e99664..677899286 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TuskyTileService.java
+++ b/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java
@@ -13,12 +13,14 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.service;
import android.annotation.TargetApi;
import android.content.Intent;
import android.service.quicksettings.TileService;
+import com.keylesspalace.tusky.ComposeActivity;
+
/**
* Small Addition that adds in a QuickSettings tile that opens the Compose activity when clicked
* Created by ztepps on 4/3/17.
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/Assert.java b/app/src/main/java/com/keylesspalace/tusky/util/Assert.java
new file mode 100644
index 000000000..c976184e5
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/Assert.java
@@ -0,0 +1,29 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+import com.keylesspalace.tusky.BuildConfig;
+
+/** Android Studio complains about built-in assertions so this is an alternative. */
+public class Assert {
+ private static boolean ENABLED = BuildConfig.DEBUG;
+
+ public static void expect(boolean expression) {
+ if (ENABLED && !expression) {
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/ConversationLineItemDecoration.java b/app/src/main/java/com/keylesspalace/tusky/util/ConversationLineItemDecoration.java
similarity index 89%
rename from app/src/main/java/com/keylesspalace/tusky/ConversationLineItemDecoration.java
rename to app/src/main/java/com/keylesspalace/tusky/util/ConversationLineItemDecoration.java
index e5fb8562d..dab773c35 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ConversationLineItemDecoration.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ConversationLineItemDecoration.java
@@ -13,19 +13,17 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
-import android.util.TypedValue;
import android.view.View;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import com.keylesspalace.tusky.R;
-class ConversationLineItemDecoration extends RecyclerView.ItemDecoration {
+public class ConversationLineItemDecoration extends RecyclerView.ItemDecoration {
private final Context mContext;
private final Drawable mDivider;
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/CountUpDownLatch.java b/app/src/main/java/com/keylesspalace/tusky/util/CountUpDownLatch.java
new file mode 100644
index 000000000..5791cf606
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/CountUpDownLatch.java
@@ -0,0 +1,40 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+public class CountUpDownLatch {
+ private int count;
+
+ public CountUpDownLatch() {
+ this.count = 0;
+ }
+
+ public synchronized void countDown() {
+ count--;
+ notifyAll();
+ }
+
+ public synchronized void countUp() {
+ count++;
+ notifyAll();
+ }
+
+ public synchronized void await() throws InterruptedException {
+ while (count != 0) {
+ wait();
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/CustomTabURLSpan.java b/app/src/main/java/com/keylesspalace/tusky/util/CustomTabURLSpan.java
similarity index 96%
rename from app/src/main/java/com/keylesspalace/tusky/CustomTabURLSpan.java
rename to app/src/main/java/com/keylesspalace/tusky/util/CustomTabURLSpan.java
index 7af9a84fe..bef07fcf1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/CustomTabURLSpan.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/CustomTabURLSpan.java
@@ -1,4 +1,4 @@
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -11,6 +11,8 @@ import android.support.v4.content.ContextCompat;
import android.text.style.URLSpan;
import android.view.View;
+import com.keylesspalace.tusky.R;
+
class CustomTabURLSpan extends URLSpan {
CustomTabURLSpan(String url) {
super(url);
diff --git a/app/src/main/java/com/keylesspalace/tusky/CustomTabsHelper.java b/app/src/main/java/com/keylesspalace/tusky/util/CustomTabsHelper.java
similarity index 99%
rename from app/src/main/java/com/keylesspalace/tusky/CustomTabsHelper.java
rename to app/src/main/java/com/keylesspalace/tusky/util/CustomTabsHelper.java
index 456708638..f5add0475 100644
--- a/app/src/main/java/com/keylesspalace/tusky/CustomTabsHelper.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/CustomTabsHelper.java
@@ -1,4 +1,4 @@
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/DateUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/DateUtils.java
new file mode 100644
index 000000000..b2cc49a2c
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/DateUtils.java
@@ -0,0 +1,50 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+public class DateUtils {
+ /* This is a rough duplicate of android.text.format.DateUtils.getRelativeTimeSpanString,
+ * but even with the FORMAT_ABBREV_RELATIVE flag it wasn't abbreviating enough. */
+ public static String getRelativeTimeSpanString(long then, long now) {
+ final long MINUTE = 60;
+ final long HOUR = 60 * MINUTE;
+ final long DAY = 24 * HOUR;
+ final long YEAR = 365 * DAY;
+ long span = (now - then) / 1000;
+ String prefix = "";
+ if (span < 0) {
+ prefix = "in ";
+ span = -span;
+ }
+ String unit;
+ if (span < MINUTE) {
+ unit = "s";
+ } else if (span < HOUR) {
+ span /= MINUTE;
+ unit = "m";
+ } else if (span < DAY) {
+ span /= HOUR;
+ unit = "h";
+ } else if (span < YEAR) {
+ span /= DAY;
+ unit = "d";
+ } else {
+ span /= YEAR;
+ unit = "y";
+ }
+ return prefix + span + unit;
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/DownsizeImageTask.java b/app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java
similarity index 97%
rename from app/src/main/java/com/keylesspalace/tusky/DownsizeImageTask.java
rename to app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java
index 56d50ed99..0cbc35a83 100644
--- a/app/src/main/java/com/keylesspalace/tusky/DownsizeImageTask.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.ContentResolver;
import android.graphics.Bitmap;
@@ -31,13 +31,13 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
-class DownsizeImageTask extends AsyncTask {
+public class DownsizeImageTask extends AsyncTask {
private int sizeLimit;
private ContentResolver contentResolver;
private Listener listener;
private List resultList;
- DownsizeImageTask(int sizeLimit, ContentResolver contentResolver, Listener listener) {
+ public DownsizeImageTask(int sizeLimit, ContentResolver contentResolver, Listener listener) {
this.sizeLimit = sizeLimit;
this.contentResolver = contentResolver;
this.listener = listener;
@@ -219,7 +219,7 @@ class DownsizeImageTask extends AsyncTask {
super.onPostExecute(successful);
}
- interface Listener {
+ public interface Listener {
void onSuccess(List contentList);
void onFailure();
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/EditTextTyped.java b/app/src/main/java/com/keylesspalace/tusky/util/EditTextTyped.java
similarity index 98%
rename from app/src/main/java/com/keylesspalace/tusky/EditTextTyped.java
rename to app/src/main/java/com/keylesspalace/tusky/util/EditTextTyped.java
index 367180a2b..c32f666f4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/EditTextTyped.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/EditTextTyped.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.Context;
import android.support.v13.view.inputmethod.EditorInfoCompat;
diff --git a/app/src/main/java/com/keylesspalace/tusky/EndlessOnScrollListener.java b/app/src/main/java/com/keylesspalace/tusky/util/EndlessOnScrollListener.java
similarity index 90%
rename from app/src/main/java/com/keylesspalace/tusky/EndlessOnScrollListener.java
rename to app/src/main/java/com/keylesspalace/tusky/util/EndlessOnScrollListener.java
index 9c91a89a1..0b149de05 100644
--- a/app/src/main/java/com/keylesspalace/tusky/EndlessOnScrollListener.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/EndlessOnScrollListener.java
@@ -13,12 +13,12 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
-abstract class EndlessOnScrollListener extends RecyclerView.OnScrollListener {
+public abstract class EndlessOnScrollListener extends RecyclerView.OnScrollListener {
private static final int VISIBLE_THRESHOLD = 15;
private int currentPage;
private int previousTotalItemCount;
@@ -26,7 +26,7 @@ abstract class EndlessOnScrollListener extends RecyclerView.OnScrollListener {
private int startingPageIndex;
private LinearLayoutManager layoutManager;
- EndlessOnScrollListener(LinearLayoutManager layoutManager) {
+ public EndlessOnScrollListener(LinearLayoutManager layoutManager) {
this.layoutManager = layoutManager;
currentPage = 0;
previousTotalItemCount = 0;
@@ -56,7 +56,7 @@ abstract class EndlessOnScrollListener extends RecyclerView.OnScrollListener {
}
}
- void reset() {
+ public void reset() {
currentPage = startingPageIndex;
previousTotalItemCount = 0;
loading = true;
diff --git a/app/src/main/java/com/keylesspalace/tusky/FlowLayout.java b/app/src/main/java/com/keylesspalace/tusky/util/FlowLayout.java
similarity index 98%
rename from app/src/main/java/com/keylesspalace/tusky/FlowLayout.java
rename to app/src/main/java/com/keylesspalace/tusky/util/FlowLayout.java
index 44616643a..cf1f9e686 100644
--- a/app/src/main/java/com/keylesspalace/tusky/FlowLayout.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/FlowLayout.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.Context;
import android.content.res.TypedArray;
@@ -21,6 +21,8 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import com.keylesspalace.tusky.R;
+
public class FlowLayout extends ViewGroup {
private int paddingHorizontal; // internal padding between child views
private int paddingVertical; //
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/HtmlUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/HtmlUtils.java
new file mode 100644
index 000000000..eee9bb44d
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/HtmlUtils.java
@@ -0,0 +1,54 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+import android.os.Build;
+import android.text.Html;
+import android.text.Spanned;
+
+public class HtmlUtils {
+ private static CharSequence trimTrailingWhitespace(CharSequence s) {
+ int i = s.length();
+ do {
+ i--;
+ } while (i >= 0 && Character.isWhitespace(s.charAt(i)));
+ return s.subSequence(0, i + 1);
+ }
+
+ @SuppressWarnings("deprecation")
+ public static Spanned fromHtml(String html) {
+ Spanned result;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
+ } else {
+ result = Html.fromHtml(html);
+ }
+ /* Html.fromHtml returns trailing whitespace if the html ends in a
tag, which
+ * all status contents do, so it should be trimmed. */
+ return (Spanned) trimTrailingWhitespace(result);
+ }
+
+ @SuppressWarnings("deprecation")
+ public static String toHtml(Spanned text) {
+ String result;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ result = Html.toHtml(text, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);
+ } else {
+ result = Html.toHtml(text);
+ }
+ return result;
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.java
new file mode 100644
index 000000000..2b17eeeb1
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.java
@@ -0,0 +1,44 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+import android.support.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class IOUtils {
+ public static void closeQuietly(@Nullable InputStream stream) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // intentionally unhandled
+ }
+ }
+
+ public static void closeQuietly(@Nullable OutputStream stream) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // intentionally unhandled
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/LinkHelper.java b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
similarity index 87%
rename from app/src/main/java/com/keylesspalace/tusky/LinkHelper.java
rename to app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
index ba9a591fe..46ddd5f17 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LinkHelper.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
@@ -13,9 +13,8 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
-import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@@ -26,14 +25,13 @@ import android.view.View;
import android.widget.TextView;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.interfaces.LinkListener;
-class LinkHelper {
- static void setClickableText(TextView view, Spanned content,
- @Nullable Status.Mention[] mentions,
- final LinkListener listener) {
+public class LinkHelper {
+ public static void setClickableText(TextView view, Spanned content,
+ @Nullable Status.Mention[] mentions, boolean useCustomTabs,
+ final LinkListener listener) {
SpannableStringBuilder builder = new SpannableStringBuilder(content);
- boolean useCustomTabs = PreferenceManager.getDefaultSharedPreferences(view.getContext())
- .getBoolean("customTabs", true);
URLSpan[] urlSpans = content.getSpans(0, content.length(), URLSpan.class);
for (URLSpan span : urlSpans) {
int start = builder.getSpanStart(span);
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/Log.java b/app/src/main/java/com/keylesspalace/tusky/util/Log.java
new file mode 100644
index 000000000..26d3d85fe
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/Log.java
@@ -0,0 +1,53 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+import com.keylesspalace.tusky.BuildConfig;
+
+/**A wrapper for android.util.Log that allows for disabling logging, such as for release builds.*/
+public class Log {
+ private static final boolean LOGGING_ENABLED = BuildConfig.DEBUG;
+
+ public static void i(String tag, String string) {
+ if (LOGGING_ENABLED) {
+ android.util.Log.i(tag, string);
+ }
+ }
+
+ public static void e(String tag, String string) {
+ if (LOGGING_ENABLED) {
+ android.util.Log.e(tag, string);
+ }
+ }
+
+ public static void d(String tag, String string) {
+ if (LOGGING_ENABLED) {
+ android.util.Log.d(tag, string);
+ }
+ }
+
+ public static void v(String tag, String string) {
+ if (LOGGING_ENABLED) {
+ android.util.Log.v(tag, string);
+ }
+ }
+
+ public static void w(String tag, String string) {
+ if (LOGGING_ENABLED) {
+ android.util.Log.w(tag, string);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationClearBroadcastReceiver.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationClearBroadcastReceiver.java
similarity index 97%
rename from app/src/main/java/com/keylesspalace/tusky/NotificationClearBroadcastReceiver.java
rename to app/src/main/java/com/keylesspalace/tusky/util/NotificationClearBroadcastReceiver.java
index 9508dac6a..d18902e36 100644
--- a/app/src/main/java/com/keylesspalace/tusky/NotificationClearBroadcastReceiver.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationClearBroadcastReceiver.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.content.BroadcastReceiver;
import android.content.Context;
diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationMaker.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java
similarity index 97%
rename from app/src/main/java/com/keylesspalace/tusky/NotificationMaker.java
rename to app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java
index 8c7bfb85d..e5bc70033 100644
--- a/app/src/main/java/com/keylesspalace/tusky/NotificationMaker.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -29,6 +29,8 @@ import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
+import com.keylesspalace.tusky.MainActivity;
+import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Notification;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
@@ -36,8 +38,8 @@ import com.squareup.picasso.Target;
import org.json.JSONArray;
import org.json.JSONException;
-class NotificationMaker {
- static void make(final Context context, final int notifyId, Notification body) {
+public class NotificationMaker {
+ public static void make(final Context context, final int notifyId, Notification body) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences notificationPreferences = context.getSharedPreferences(
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
new file mode 100644
index 000000000..c90002d20
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
@@ -0,0 +1,244 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is part of Tusky.
+ *
+ * Tusky is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * Lesser General Public License as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * Tusky 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with Tusky. If
+ * not, see . */
+
+package com.keylesspalace.tusky.util;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+import com.keylesspalace.tusky.BuildConfig;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import okhttp3.ConnectionSpec;
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class OkHttpUtils {
+ static final String TAG = "OkHttpUtils"; // logging tag
+
+ /**
+ * Makes a Builder with the maximum range of TLS versions and cipher suites enabled.
+ *
+ * It first tries the "approved" list of cipher suites given in OkHttp (the default in
+ * ConnectionSpec.MODERN_TLS) and if that doesn't work falls back to the set of ALL enabled,
+ * then falls back to plain http.
+ *
+ * API level 24 has a regression in elliptic curves where it only supports secp256r1, so this
+ * first tries a fallback without elliptic curves at all, and then tries them after.
+ *
+ * TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20.
+ */
+ @NonNull
+ public static OkHttpClient.Builder getCompatibleClientBuilder() {
+ ConnectionSpec fallback = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
+ .allEnabledCipherSuites()
+ .supportsTlsExtensions(true)
+ .build();
+
+ List specList = new ArrayList<>();
+ specList.add(ConnectionSpec.MODERN_TLS);
+ addNougatFixConnectionSpec(specList);
+ specList.add(fallback);
+ specList.add(ConnectionSpec.CLEARTEXT);
+
+ OkHttpClient.Builder builder = new OkHttpClient.Builder()
+ .addInterceptor(getUserAgentInterceptor())
+ .connectionSpecs(specList);
+
+ return enableHigherTlsOnPreLollipop(builder);
+ }
+
+ @NonNull
+ public static OkHttpClient getCompatibleClient() {
+ return getCompatibleClientBuilder().build();
+ }
+
+ /**
+ * Add a custom User-Agent that contains Tusky & Android Version to all requests
+ * Example:
+ * User-Agent: Tusky/1.1.2 Android/5.0.2
+ */
+ @NonNull
+ private static Interceptor getUserAgentInterceptor() {
+ return new Interceptor() {
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request originalRequest = chain.request();
+ Request requestWithUserAgent = originalRequest.newBuilder()
+ .header("User-Agent", "Tusky/"+ BuildConfig.VERSION_NAME+" Android/"+Build.VERSION.RELEASE)
+ .build();
+ return chain.proceed(requestWithUserAgent);
+ }
+ };
+ }
+
+
+ /**
+ * Android version Nougat has a regression where elliptic curve cipher suites are supported, but
+ * only the curve secp256r1 is allowed. So, first it's best to just disable all elliptic
+ * ciphers, try the connection, and fall back to the all cipher suites enabled list after.
+ */
+ private static void addNougatFixConnectionSpec(List specList) {
+ if (Build.VERSION.SDK_INT != Build.VERSION_CODES.N) {
+ return;
+ }
+ SSLSocketFactory socketFactory;
+ try {
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init((KeyStore) null);
+ TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+ if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
+ throw new IllegalStateException("Unexpected default trust managers:"
+ + Arrays.toString(trustManagers));
+ }
+
+ X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, new TrustManager[] { trustManager }, null);
+ socketFactory = sslContext.getSocketFactory();
+ } catch (NoSuchAlgorithmException|KeyStoreException|KeyManagementException e) {
+ Log.e(TAG, "Failed obtaining the SSL socket factory.");
+ return;
+ }
+ String[] cipherSuites = socketFactory.getDefaultCipherSuites();
+ ArrayList allowedList = new ArrayList<>();
+ for (String suite : cipherSuites) {
+ if (!suite.contains("ECDH")) {
+ allowedList.add(suite);
+ }
+ }
+ ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
+ .cipherSuites(allowedList.toArray(new String[0]))
+ .supportsTlsExtensions(true)
+ .build();
+ specList.add(spec);
+ }
+
+ private static OkHttpClient.Builder enableHigherTlsOnPreLollipop(OkHttpClient.Builder builder) {
+ if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) {
+ try {
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init((KeyStore) null);
+ TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+ if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
+ throw new IllegalStateException("Unexpected default trust managers:"
+ + Arrays.toString(trustManagers));
+ }
+
+ X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, new TrustManager[] { trustManager }, null);
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ builder.sslSocketFactory(new SSLSocketFactoryCompat(sslSocketFactory),
+ trustManager);
+ } catch (NoSuchAlgorithmException|KeyStoreException|KeyManagementException e) {
+ Log.e(TAG, "Failed enabling TLS 1.1 & 1.2. " + e.getMessage());
+ }
+ }
+
+ return builder;
+ }
+
+ private static class SSLSocketFactoryCompat extends SSLSocketFactory {
+ private static final String[] DESIRED_TLS_VERSIONS = { "TLSv1", "TLSv1.1", "TLSv1.2",
+ "TLSv1.3" };
+
+ final SSLSocketFactory delegate;
+
+ SSLSocketFactoryCompat(SSLSocketFactory base) {
+ this.delegate = base;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return delegate.getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return delegate.getSupportedCipherSuites();
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ throws IOException {
+ return patch(delegate.createSocket(s, host, port, autoClose));
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ return patch(delegate.createSocket(host, port));
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException {
+ return patch(delegate.createSocket(host, port, localHost, localPort));
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ return patch(delegate.createSocket(host, port));
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ return patch(delegate.createSocket(address, port, localAddress, localPort));
+ }
+
+ @NonNull
+ private static String[] getMatches(String[] wanted, String[] have) {
+ List a = new ArrayList<>(Arrays.asList(wanted));
+ List b = Arrays.asList(have);
+ a.retainAll(b);
+ return a.toArray(new String[0]);
+ }
+
+ private Socket patch(Socket socket) {
+ if (socket instanceof SSLSocket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ String[] protocols = getMatches(DESIRED_TLS_VERSIONS,
+ sslSocket.getSupportedProtocols());
+ sslSocket.setEnabledProtocols(protocols);
+ }
+ return socket;
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/RoundedTransformation.java b/app/src/main/java/com/keylesspalace/tusky/util/RoundedTransformation.java
similarity index 98%
rename from app/src/main/java/com/keylesspalace/tusky/RoundedTransformation.java
rename to app/src/main/java/com/keylesspalace/tusky/util/RoundedTransformation.java
index bd4192b51..ff153d687 100644
--- a/app/src/main/java/com/keylesspalace/tusky/RoundedTransformation.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/RoundedTransformation.java
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky;
+package com.keylesspalace.tusky.util;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/SpanUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/SpanUtils.java
new file mode 100644
index 000000000..81a82d2b8
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/SpanUtils.java
@@ -0,0 +1,129 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+
+public class SpanUtils {
+ private static class FindCharsResult {
+ int charIndex;
+ int stringIndex;
+
+ FindCharsResult() {
+ charIndex = -1;
+ stringIndex = -1;
+ }
+ }
+
+ private static FindCharsResult findChars(String string, int fromIndex, char[] chars) {
+ FindCharsResult result = new FindCharsResult();
+ final int length = string.length();
+ for (int i = fromIndex; i < length; i++) {
+ char c = string.charAt(i);
+ for (int j = 0; j < chars.length; j++) {
+ if (chars[j] == c) {
+ result.charIndex = j;
+ result.stringIndex = i;
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ private static FindCharsResult findStart(String string, int fromIndex, char[] chars) {
+ final int length = string.length();
+ while (fromIndex < length) {
+ FindCharsResult found = findChars(string, fromIndex, chars);
+ int i = found.stringIndex;
+ if (i < 0) {
+ break;
+ } else if (i == 0 || i >= 1 && Character.isWhitespace(string.codePointBefore(i))) {
+ return found;
+ } else {
+ fromIndex = i + 1;
+ }
+ }
+ return new FindCharsResult();
+ }
+
+ private static int findEndOfHashtag(String string, int fromIndex) {
+ final int length = string.length();
+ for (int i = fromIndex + 1; i < length;) {
+ int codepoint = string.codePointAt(i);
+ if (Character.isWhitespace(codepoint)) {
+ return i;
+ } else if (codepoint == '#') {
+ return -1;
+ }
+ i += Character.charCount(codepoint);
+ }
+ return length;
+ }
+
+ private static int findEndOfMention(String string, int fromIndex) {
+ int atCount = 0;
+ final int length = string.length();
+ for (int i = fromIndex + 1; i < length;) {
+ int codepoint = string.codePointAt(i);
+ if (Character.isWhitespace(codepoint)) {
+ return i;
+ } else if (codepoint == '@') {
+ atCount += 1;
+ if (atCount >= 2) {
+ return -1;
+ }
+ }
+ i += Character.charCount(codepoint);
+ }
+ return length;
+ }
+
+ public static void highlightSpans(Spannable text, int colour) {
+ // Strip all existing colour spans.
+ int n = text.length();
+ ForegroundColorSpan[] oldSpans = text.getSpans(0, n, ForegroundColorSpan.class);
+ for (int i = oldSpans.length - 1; i >= 0; i--) {
+ text.removeSpan(oldSpans[i]);
+ }
+ // Colour the mentions and hashtags.
+ String string = text.toString();
+ int start;
+ int end = 0;
+ while (end < n) {
+ char[] chars = { '#', '@' };
+ FindCharsResult found = findStart(string, end, chars);
+ start = found.stringIndex;
+ if (start < 0) {
+ break;
+ }
+ if (found.charIndex == 0) {
+ end = findEndOfHashtag(string, start);
+ } else if (found.charIndex == 1) {
+ end = findEndOfMention(string, start);
+ } else {
+ break;
+ }
+ if (end < 0) {
+ break;
+ }
+ text.setSpan(new ForegroundColorSpan(colour), start, end,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java
new file mode 100644
index 000000000..310341faf
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java
@@ -0,0 +1,68 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.util;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.AttrRes;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
+import android.util.TypedValue;
+import android.widget.ImageView;
+
+public class ThemeUtils {
+ public static Drawable getDrawable(Context context, @AttrRes int attribute,
+ @DrawableRes int fallbackDrawable) {
+ TypedValue value = new TypedValue();
+ @DrawableRes int resourceId;
+ if (context.getTheme().resolveAttribute(attribute, value, true)) {
+ resourceId = value.resourceId;
+ } else {
+ resourceId = fallbackDrawable;
+ }
+ return ContextCompat.getDrawable(context, resourceId);
+ }
+
+ public static @DrawableRes int getDrawableId(Context context, @AttrRes int attribute,
+ @DrawableRes int fallbackDrawableId) {
+ TypedValue value = new TypedValue();
+ if (context.getTheme().resolveAttribute(attribute, value, true)) {
+ return value.resourceId;
+ } else {
+ return fallbackDrawableId;
+ }
+ }
+
+ public static @ColorInt int getColor(Context context, @AttrRes int attribute) {
+ TypedValue value = new TypedValue();
+ if (context.getTheme().resolveAttribute(attribute, value, true)) {
+ return value.data;
+ } else {
+ return Color.BLACK;
+ }
+ }
+
+ public static void setImageViewTint(ImageView view, @AttrRes int attribute) {
+ view.setColorFilter(getColor(view.getContext(), attribute), PorterDuff.Mode.SRC_IN);
+ }
+
+ public static void setDrawableTint(Context context, Drawable drawable, @AttrRes int attribute) {
+ drawable.setColorFilter(getColor(context, attribute), PorterDuff.Mode.SRC_IN);
+ }
+}
diff --git a/app/src/main/res/layout/activity_compose.xml b/app/src/main/res/layout/activity_compose.xml
index 9807e944b..0252cce7b 100644
--- a/app/src/main/res/layout/activity_compose.xml
+++ b/app/src/main/res/layout/activity_compose.xml
@@ -54,7 +54,7 @@
android:paddingLeft="16dp"
android:paddingRight="16dp">
-
-
-
+