Merge branch 'Gargron-master'
This commit is contained in:
commit
e21472b8cc
33 changed files with 698 additions and 462 deletions
|
@ -25,6 +25,9 @@ dependencies {
|
||||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||||
exclude group: 'com.android.support', module: 'support-annotations'
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
})
|
})
|
||||||
|
compile('com.mikepenz:materialdrawer:5.8.2@aar') {
|
||||||
|
transitive = true
|
||||||
|
}
|
||||||
compile 'com.android.support:appcompat-v7:25.2.0'
|
compile 'com.android.support:appcompat-v7:25.2.0'
|
||||||
compile 'com.android.support:recyclerview-v7:25.2.0'
|
compile 'com.android.support:recyclerview-v7:25.2.0'
|
||||||
compile 'com.android.support:support-v13:25.2.0'
|
compile 'com.android.support:support-v13:25.2.0'
|
||||||
|
@ -32,16 +35,19 @@ dependencies {
|
||||||
compile 'com.squareup.picasso:picasso:2.5.2'
|
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||||
compile 'com.pkmmte.view:circularimageview:1.1'
|
compile 'com.pkmmte.view:circularimageview:1.1'
|
||||||
compile 'com.github.peter9870:sparkbutton:master'
|
compile 'com.github.peter9870:sparkbutton:master'
|
||||||
testCompile 'junit:junit:4.12'
|
|
||||||
compile 'com.mikhaellopez:circularfillableloaders:1.2.0'
|
compile 'com.mikhaellopez:circularfillableloaders:1.2.0'
|
||||||
compile 'com.squareup.retrofit2:retrofit:2.2.0'
|
compile 'com.squareup.retrofit2:retrofit:2.2.0'
|
||||||
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
|
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
|
||||||
compile('com.mikepenz:materialdrawer:5.8.2@aar') {
|
|
||||||
transitive = true
|
|
||||||
}
|
|
||||||
compile 'com.github.chrisbanes:PhotoView:1.3.1'
|
compile 'com.github.chrisbanes:PhotoView:1.3.1'
|
||||||
compile 'com.mikepenz:google-material-typeface:3.0.1.0.original@aar'
|
compile 'com.mikepenz:google-material-typeface:3.0.1.0.original@aar'
|
||||||
compile 'com.github.arimorty:floatingsearchview:2.0.3'
|
compile 'com.github.arimorty:floatingsearchview:2.0.3'
|
||||||
compile 'com.jakewharton:butterknife:8.4.0'
|
compile 'com.jakewharton:butterknife:8.4.0'
|
||||||
|
compile 'com.google.firebase:firebase-messaging:10.0.1'
|
||||||
|
compile 'com.google.firebase:firebase-crash:10.0.1'
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -17,22 +17,27 @@
|
||||||
android:theme="@android:style/Theme.Black.NoTitleBar">
|
android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".LoginActivity">
|
<activity android:name=".LoginActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="@string/oauth_scheme" android:host="@string/oauth_redirect_host" />
|
|
||||||
|
<data
|
||||||
|
android:host="@string/oauth_redirect_host"
|
||||||
|
android:scheme="@string/oauth_scheme" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".MainActivity" />
|
<activity android:name=".MainActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ComposeActivity"
|
android:name=".ComposeActivity"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize" />
|
android:windowSoftInputMode="stateVisible|adjustResize" />
|
||||||
<activity android:name=".ViewVideoActivity" />
|
<activity android:name=".ViewVideoActivity" android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||||
<activity android:name=".ViewThreadActivity" />
|
<activity android:name=".ViewThreadActivity" />
|
||||||
<activity android:name=".ViewTagActivity" />
|
<activity android:name=".ViewTagActivity" />
|
||||||
<activity android:name=".AccountActivity" />
|
<activity android:name=".AccountActivity" />
|
||||||
|
@ -42,10 +47,17 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".ReportActivity"
|
android:name=".ReportActivity"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize" />
|
android:windowSoftInputMode="stateVisible|adjustResize" />
|
||||||
<service
|
|
||||||
android:name=".PullNotificationService"
|
<service android:name=".MyFirebaseInstanceIdService" android:exported="true">
|
||||||
android:description="@string/notification_service_description"
|
<intent-filter>
|
||||||
android:exported="false" />
|
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
<service android:name=".MyFirebaseMessagingService" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -47,12 +47,14 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
* activity extend from it. */
|
* activity extend from it. */
|
||||||
public class BaseActivity extends AppCompatActivity {
|
public class BaseActivity extends AppCompatActivity {
|
||||||
protected MastodonAPI mastodonAPI;
|
protected MastodonAPI mastodonAPI;
|
||||||
|
protected TuskyAPI tuskyAPI;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
createMastodonAPI();
|
createMastodonAPI();
|
||||||
|
createTuskyAPI();
|
||||||
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("lightTheme", false)) {
|
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("lightTheme", false)) {
|
||||||
setTheme(R.style.AppTheme_Light);
|
setTheme(R.style.AppTheme_Light);
|
||||||
|
@ -121,6 +123,14 @@ public class BaseActivity extends AppCompatActivity {
|
||||||
mastodonAPI = retrofit.create(MastodonAPI.class);
|
mastodonAPI = retrofit.create(MastodonAPI.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void createTuskyAPI() {
|
||||||
|
Retrofit retrofit = new Retrofit.Builder()
|
||||||
|
.baseUrl(getString(R.string.tusky_api_url))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
tuskyAPI = retrofit.create(TuskyAPI.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
TypedValue value = new TypedValue();
|
TypedValue value = new TypedValue();
|
||||||
|
|
|
@ -20,15 +20,20 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
|
import com.pkmmte.view.CircularImageView;
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
class BlocksAdapter extends AccountAdapter {
|
class BlocksAdapter extends AccountAdapter {
|
||||||
private static final int VIEW_TYPE_BLOCKED_USER = 0;
|
private static final int VIEW_TYPE_BLOCKED_USER = 0;
|
||||||
private static final int VIEW_TYPE_FOOTER = 1;
|
private static final int VIEW_TYPE_FOOTER = 1;
|
||||||
|
@ -88,19 +93,17 @@ class BlocksAdapter extends AccountAdapter {
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BlockedUserViewHolder extends RecyclerView.ViewHolder {
|
static class BlockedUserViewHolder extends RecyclerView.ViewHolder {
|
||||||
private ImageView avatar;
|
@BindView(R.id.blocked_user_avatar) CircularImageView avatar;
|
||||||
private TextView username;
|
@BindView(R.id.blocked_user_username) TextView username;
|
||||||
private TextView displayName;
|
@BindView(R.id.blocked_user_display_name) TextView displayName;
|
||||||
private Button unblock;
|
@BindView(R.id.blocked_user_unblock) ImageButton unblock;
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
BlockedUserViewHolder(View itemView) {
|
BlockedUserViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
avatar = (ImageView) itemView.findViewById(R.id.blocked_user_avatar);
|
ButterKnife.bind(this, itemView);
|
||||||
displayName = (TextView) itemView.findViewById(R.id.blocked_user_display_name);
|
|
||||||
username = (TextView) itemView.findViewById(R.id.blocked_user_username);
|
|
||||||
unblock = (Button) itemView.findViewById(R.id.blocked_user_unblock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
void setupWithAccount(Account account) {
|
||||||
|
@ -118,13 +121,6 @@ class BlocksAdapter extends AccountAdapter {
|
||||||
|
|
||||||
void setupActionListener(final AccountActionListener listener, final boolean blocked,
|
void setupActionListener(final AccountActionListener listener, final boolean blocked,
|
||||||
final int position) {
|
final int position) {
|
||||||
int unblockTextId;
|
|
||||||
if (blocked) {
|
|
||||||
unblockTextId = R.string.action_unblock;
|
|
||||||
} else {
|
|
||||||
unblockTextId = R.string.action_block;
|
|
||||||
}
|
|
||||||
unblock.setText(unblock.getContext().getString(unblockTextId));
|
|
||||||
unblock.setOnClickListener(new View.OnClickListener() {
|
unblock.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
class ConversationLineItemDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
private final Context mContext;
|
||||||
|
private final Drawable mDivider;
|
||||||
|
|
||||||
|
public ConversationLineItemDecoration(Context context, Drawable divider) {
|
||||||
|
mContext = context;
|
||||||
|
mDivider = divider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
// Fun fact: this method draws in pixels, but all layouts are in DP, so I'm using the divider's
|
||||||
|
// own 2dp width to calculate what I want
|
||||||
|
int dividerLeft = parent.getPaddingLeft() + mContext.getResources().getDimensionPixelSize(R.dimen.status_left_line_margin);
|
||||||
|
int dividerRight = dividerLeft + mDivider.getIntrinsicWidth();
|
||||||
|
|
||||||
|
int childCount = parent.getChildCount();
|
||||||
|
int avatarMargin = mContext.getResources().getDimensionPixelSize(R.dimen.account_avatar_margin);
|
||||||
|
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
View child = parent.getChildAt(i);
|
||||||
|
|
||||||
|
int dividerTop = child.getTop() + (i == 0 ? avatarMargin : 0);
|
||||||
|
int dividerBottom = (i == childCount - 1 ? child.getTop() + avatarMargin : child.getBottom());
|
||||||
|
|
||||||
|
mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
|
||||||
|
mDivider.draw(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,8 +24,11 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
|
import com.pkmmte.view.CircularImageView;
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
/** Both for follows and following lists. */
|
/** Both for follows and following lists. */
|
||||||
class FollowAdapter extends AccountAdapter {
|
class FollowAdapter extends AccountAdapter {
|
||||||
private static final int VIEW_TYPE_ACCOUNT = 0;
|
private static final int VIEW_TYPE_ACCOUNT = 0;
|
||||||
|
@ -77,8 +80,7 @@ class FollowAdapter extends AccountAdapter {
|
||||||
private View container;
|
private View container;
|
||||||
private TextView username;
|
private TextView username;
|
||||||
private TextView displayName;
|
private TextView displayName;
|
||||||
private TextView note;
|
private CircularImageView avatar;
|
||||||
private ImageView avatar;
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
AccountViewHolder(View itemView) {
|
AccountViewHolder(View itemView) {
|
||||||
|
@ -86,8 +88,7 @@ class FollowAdapter extends AccountAdapter {
|
||||||
container = itemView.findViewById(R.id.account_container);
|
container = itemView.findViewById(R.id.account_container);
|
||||||
username = (TextView) itemView.findViewById(R.id.account_username);
|
username = (TextView) itemView.findViewById(R.id.account_username);
|
||||||
displayName = (TextView) itemView.findViewById(R.id.account_display_name);
|
displayName = (TextView) itemView.findViewById(R.id.account_display_name);
|
||||||
note = (TextView) itemView.findViewById(R.id.account_note);
|
avatar = (CircularImageView) itemView.findViewById(R.id.account_avatar);
|
||||||
avatar = (ImageView) itemView.findViewById(R.id.account_avatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
void setupWithAccount(Account account) {
|
||||||
|
@ -96,7 +97,6 @@ class FollowAdapter extends AccountAdapter {
|
||||||
String formattedUsername = String.format(format, account.username);
|
String formattedUsername = String.format(format, account.username);
|
||||||
username.setText(formattedUsername);
|
username.setText(formattedUsername);
|
||||||
displayName.setText(account.getDisplayName());
|
displayName.setText(account.getDisplayName());
|
||||||
note.setText(account.note);
|
|
||||||
Context context = avatar.getContext();
|
Context context = avatar.getContext();
|
||||||
Picasso.with(context)
|
Picasso.with(context)
|
||||||
.load(account.avatar)
|
.load(account.avatar)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -27,6 +28,7 @@ import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.support.design.widget.TabLayout;
|
import android.support.design.widget.TabLayout;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
@ -41,6 +43,7 @@ import android.widget.TextView;
|
||||||
import com.arlib.floatingsearchview.FloatingSearchView;
|
import com.arlib.floatingsearchview.FloatingSearchView;
|
||||||
import com.arlib.floatingsearchview.suggestions.SearchSuggestionsAdapter;
|
import com.arlib.floatingsearchview.suggestions.SearchSuggestionsAdapter;
|
||||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion;
|
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion;
|
||||||
|
import com.google.firebase.iid.FirebaseInstanceId;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
|
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
|
||||||
import com.mikepenz.materialdrawer.AccountHeader;
|
import com.mikepenz.materialdrawer.AccountHeader;
|
||||||
|
@ -60,6 +63,9 @@ import com.squareup.picasso.Picasso;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
|
@ -67,28 +73,27 @@ import retrofit2.Response;
|
||||||
public class MainActivity extends BaseActivity {
|
public class MainActivity extends BaseActivity {
|
||||||
private static final String TAG = "MainActivity"; // logging tag and Volley request tag
|
private static final String TAG = "MainActivity"; // logging tag and Volley request tag
|
||||||
|
|
||||||
private AlarmManager alarmManager;
|
|
||||||
private PendingIntent serviceAlarmIntent;
|
|
||||||
private boolean notificationServiceEnabled;
|
|
||||||
private String loggedInAccountId;
|
private String loggedInAccountId;
|
||||||
private String loggedInAccountUsername;
|
private String loggedInAccountUsername;
|
||||||
Stack<Integer> pageHistory = new Stack<Integer>();
|
Stack<Integer> pageHistory = new Stack<Integer>();
|
||||||
private ViewPager viewPager;
|
|
||||||
private AccountHeader headerResult;
|
private AccountHeader headerResult;
|
||||||
private Drawer drawer;
|
private Drawer drawer;
|
||||||
|
|
||||||
|
@BindView(R.id.floating_search_view) FloatingSearchView searchView;
|
||||||
|
@BindView(R.id.floating_btn) FloatingActionButton floatingBtn;
|
||||||
|
@BindView(R.id.tab_layout) TabLayout tabLayout;
|
||||||
|
@BindView(R.id.pager) ViewPager viewPager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
// Fetch user info while we're doing other things.
|
// Fetch user info while we're doing other things.
|
||||||
fetchUserInfo();
|
fetchUserInfo();
|
||||||
|
|
||||||
//Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
|
||||||
//setSupportActionBar(toolbar);
|
|
||||||
|
|
||||||
FloatingActionButton floatingBtn = (FloatingActionButton) findViewById(R.id.floating_btn);
|
|
||||||
floatingBtn.setOnClickListener(new View.OnClickListener() {
|
floatingBtn.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -97,8 +102,93 @@ public class MainActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final FloatingSearchView searchView = (FloatingSearchView) findViewById(R.id.floating_search_view);
|
setupDrawer();
|
||||||
|
setupSearchView();
|
||||||
|
|
||||||
|
// Setup the tabs and timeline pager.
|
||||||
|
TimelinePagerAdapter adapter = new TimelinePagerAdapter(getSupportFragmentManager());
|
||||||
|
String[] pageTitles = {
|
||||||
|
getString(R.string.title_home),
|
||||||
|
getString(R.string.title_notifications),
|
||||||
|
getString(R.string.title_public)
|
||||||
|
};
|
||||||
|
adapter.setPageTitles(pageTitles);
|
||||||
|
|
||||||
|
int pageMargin = getResources().getDimensionPixelSize(R.dimen.tab_page_margin);
|
||||||
|
viewPager.setPageMargin(pageMargin);
|
||||||
|
Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
|
||||||
|
R.drawable.tab_page_margin_dark);
|
||||||
|
viewPager.setPageMarginDrawable(pageMarginDrawable);
|
||||||
|
viewPager.setAdapter(adapter);
|
||||||
|
|
||||||
|
tabLayout.setupWithViewPager(viewPager);
|
||||||
|
|
||||||
|
tabLayout.getTabAt(0).setIcon(R.drawable.ic_home_24dp);
|
||||||
|
tabLayout.getTabAt(1).setIcon(R.drawable.ic_notifications_24dp);
|
||||||
|
tabLayout.getTabAt(2).setIcon(R.drawable.ic_public_24dp);
|
||||||
|
|
||||||
|
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onTabSelected(TabLayout.Tab tab) {
|
||||||
|
viewPager.setCurrentItem(tab.getPosition());
|
||||||
|
|
||||||
|
if (pageHistory.empty()) {
|
||||||
|
pageHistory.push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageHistory.contains(tab.getPosition())) {
|
||||||
|
pageHistory.remove(pageHistory.indexOf(tab.getPosition()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pageHistory.push(tab.getPosition());
|
||||||
|
tintTab(tab, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(TabLayout.Tab tab) {
|
||||||
|
tintTab(tab, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(TabLayout.Tab tab) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
|
||||||
|
if (intent != null) {
|
||||||
|
int tabPosition = intent.getIntExtra("tab_position", 0);
|
||||||
|
|
||||||
|
if (tabPosition != 0) {
|
||||||
|
tabLayout.getTabAt(tabPosition).select();
|
||||||
|
tintTab(tabLayout.getTabAt(tabPosition), true);
|
||||||
|
} else {
|
||||||
|
tintTab(tabLayout.getTabAt(0), true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tintTab(tabLayout.getTabAt(0), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup push notifications
|
||||||
|
tuskyAPI.register(getBaseUrl(), getAccessToken(), FirebaseInstanceId.getInstance().getToken()).enqueue(new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tintTab(TabLayout.Tab tab, boolean tinted) {
|
||||||
|
tab.getIcon().setColorFilter(ContextCompat.getColor(this, tinted ? R.color.color_accent_dark : R.color.toolbar_icon_dark), PorterDuff.Mode.SRC_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDrawer() {
|
||||||
headerResult = new AccountHeaderBuilder()
|
headerResult = new AccountHeaderBuilder()
|
||||||
.withActivity(this)
|
.withActivity(this)
|
||||||
.withSelectionListEnabledForSingleProfile(false)
|
.withSelectionListEnabledForSingleProfile(false)
|
||||||
|
@ -152,18 +242,7 @@ public class MainActivity extends BaseActivity {
|
||||||
Intent intent = new Intent(MainActivity.this, PreferencesActivity.class);
|
Intent intent = new Intent(MainActivity.this, PreferencesActivity.class);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} else if (drawerItemIdentifier == 4) {
|
} else if (drawerItemIdentifier == 4) {
|
||||||
if (notificationServiceEnabled) {
|
logout();
|
||||||
alarmManager.cancel(serviceAlarmIntent);
|
|
||||||
}
|
|
||||||
SharedPreferences preferences = getSharedPreferences(
|
|
||||||
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
|
||||||
editor.remove("domain");
|
|
||||||
editor.remove("accessToken");
|
|
||||||
editor.apply();
|
|
||||||
Intent intent = new Intent(MainActivity.this, SplashActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +250,33 @@ public class MainActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logout() {
|
||||||
|
tuskyAPI.unregister(getBaseUrl(), getAccessToken()).enqueue(new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.remove("domain");
|
||||||
|
editor.remove("accessToken");
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSearchView() {
|
||||||
searchView.attachNavigationDrawerToMenuButton(drawer.getDrawerLayout());
|
searchView.attachNavigationDrawerToMenuButton(drawer.getDrawerLayout());
|
||||||
|
|
||||||
searchView.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() {
|
searchView.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() {
|
||||||
|
@ -237,70 +342,6 @@ public class MainActivity extends BaseActivity {
|
||||||
textView.setEllipsize(TextUtils.TruncateAt.END);
|
textView.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup the tabs and timeline pager.
|
|
||||||
TimelinePagerAdapter adapter = new TimelinePagerAdapter(getSupportFragmentManager());
|
|
||||||
String[] pageTitles = {
|
|
||||||
getString(R.string.title_home),
|
|
||||||
getString(R.string.title_notifications),
|
|
||||||
getString(R.string.title_public)
|
|
||||||
};
|
|
||||||
adapter.setPageTitles(pageTitles);
|
|
||||||
viewPager = (ViewPager) findViewById(R.id.pager);
|
|
||||||
int pageMargin = getResources().getDimensionPixelSize(R.dimen.tab_page_margin);
|
|
||||||
viewPager.setPageMargin(pageMargin);
|
|
||||||
Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
|
|
||||||
R.drawable.tab_page_margin_dark);
|
|
||||||
viewPager.setPageMarginDrawable(pageMarginDrawable);
|
|
||||||
viewPager.setAdapter(adapter);
|
|
||||||
|
|
||||||
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
|
|
||||||
tabLayout.setupWithViewPager(viewPager);
|
|
||||||
|
|
||||||
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
|
||||||
@Override
|
|
||||||
public void onTabSelected(TabLayout.Tab tab) {
|
|
||||||
viewPager.setCurrentItem(tab.getPosition());
|
|
||||||
|
|
||||||
if (pageHistory.empty()) {
|
|
||||||
pageHistory.push(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageHistory.contains(tab.getPosition())) {
|
|
||||||
pageHistory.remove(pageHistory.indexOf(tab.getPosition()));
|
|
||||||
}
|
|
||||||
|
|
||||||
pageHistory.push(tab.getPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTabUnselected(TabLayout.Tab tab) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTabReselected(TabLayout.Tab tab) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Retrieve notification update preference.
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
notificationServiceEnabled = preferences.getBoolean("pullNotifications", true);
|
|
||||||
String minutesString = preferences.getString("pullNotificationCheckInterval", "15");
|
|
||||||
long notificationCheckInterval = 60 * 1000 * Integer.valueOf(minutesString);
|
|
||||||
// Start up the PullNotificationsService.
|
|
||||||
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
|
||||||
Intent intent = new Intent(this, PullNotificationService.class);
|
|
||||||
final int SERVICE_REQUEST_CODE = 8574603; // This number is arbitrary.
|
|
||||||
serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE, intent,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
if (notificationServiceEnabled) {
|
|
||||||
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime(), notificationCheckInterval, serviceAlarmIntent);
|
|
||||||
} else {
|
|
||||||
alarmManager.cancel(serviceAlarmIntent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchUserInfo() {
|
private void fetchUserInfo() {
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import com.google.firebase.iid.FirebaseInstanceId;
|
||||||
|
import com.google.firebase.iid.FirebaseInstanceIdService;
|
||||||
|
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
|
||||||
|
public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {
|
||||||
|
|
||||||
|
private TuskyAPI tuskyAPI;
|
||||||
|
|
||||||
|
protected void createTuskyAPI() {
|
||||||
|
Retrofit retrofit = new Retrofit.Builder()
|
||||||
|
.baseUrl(getString(R.string.tusky_api_url))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
tuskyAPI = retrofit.create(TuskyAPI.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTokenRefresh() {
|
||||||
|
createTuskyAPI();
|
||||||
|
|
||||||
|
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
|
||||||
|
SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
||||||
|
String accessToken = preferences.getString("accessToken", null);
|
||||||
|
String domain = preferences.getString("domain", null);
|
||||||
|
|
||||||
|
if (accessToken != null && domain != null) {
|
||||||
|
tuskyAPI.unregister("https://" + domain, accessToken).enqueue(new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tuskyAPI.register("https://" + domain, accessToken, refreshedToken).enqueue(new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.support.v4.app.TaskStackBuilder;
|
||||||
|
import android.text.Spanned;
|
||||||
|
|
||||||
|
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||||
|
import com.google.firebase.messaging.RemoteMessage;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.keylesspalace.tusky.entity.Notification;
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
import com.squareup.picasso.Target;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
|
public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||||
|
private MastodonAPI mastodonAPI;
|
||||||
|
private static final String TAG = "MyFirebaseMessagingService";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||||
|
Log.d(TAG, remoteMessage.getFrom());
|
||||||
|
Log.d(TAG, remoteMessage.toString());
|
||||||
|
|
||||||
|
String notificationId = remoteMessage.getData().get("notification_id");
|
||||||
|
|
||||||
|
if (notificationId == null) {
|
||||||
|
Log.e(TAG, "No notification ID in payload!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, notificationId);
|
||||||
|
|
||||||
|
createMastodonAPI();
|
||||||
|
|
||||||
|
mastodonAPI.notification(notificationId).enqueue(new Callback<Notification>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<Notification> call, Response<Notification> response) {
|
||||||
|
buildNotification(response.body());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<Notification> call, Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createMastodonAPI() {
|
||||||
|
SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
||||||
|
final String domain = preferences.getString("domain", null);
|
||||||
|
final String accessToken = preferences.getString("accessToken", null);
|
||||||
|
|
||||||
|
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||||
|
.addInterceptor(new Interceptor() {
|
||||||
|
@Override
|
||||||
|
public okhttp3.Response intercept(Chain chain) throws IOException {
|
||||||
|
Request originalRequest = chain.request();
|
||||||
|
|
||||||
|
Request.Builder builder = originalRequest.newBuilder()
|
||||||
|
.header("Authorization", String.format("Bearer %s", accessToken));
|
||||||
|
|
||||||
|
Request newRequest = builder.build();
|
||||||
|
|
||||||
|
return chain.proceed(newRequest);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Spanned.class, new SpannedTypeAdapter())
|
||||||
|
.create();
|
||||||
|
|
||||||
|
Retrofit retrofit = new Retrofit.Builder()
|
||||||
|
.baseUrl("https://" + domain)
|
||||||
|
.client(okHttpClient)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mastodonAPI = retrofit.create(MastodonAPI.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String truncateWithEllipses(String string, int limit) {
|
||||||
|
if (string.length() < limit) {
|
||||||
|
return string;
|
||||||
|
} else {
|
||||||
|
return string.substring(0, limit - 3) + "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildNotification(Notification body) {
|
||||||
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
Intent resultIntent = new Intent(this, MainActivity.class);
|
||||||
|
resultIntent.putExtra("tab_position", 1);
|
||||||
|
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
|
||||||
|
stackBuilder.addParentStack(MainActivity.class);
|
||||||
|
stackBuilder.addNextIntent(resultIntent);
|
||||||
|
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
|
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
|
||||||
|
.setSmallIcon(R.drawable.ic_notify)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentIntent(resultPendingIntent)
|
||||||
|
.setDefaults(0); // So it doesn't ring twice, notify only in Target callback
|
||||||
|
|
||||||
|
final Integer mId = (int)(System.currentTimeMillis() / 1000);
|
||||||
|
|
||||||
|
Target mTarget = new Target() {
|
||||||
|
@Override
|
||||||
|
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||||
|
builder.setLargeIcon(bitmap);
|
||||||
|
|
||||||
|
if (preferences.getBoolean("notificationAlertSound", true)) {
|
||||||
|
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferences.getBoolean("notificationStyleVibrate", false)) {
|
||||||
|
builder.setVibrate(new long[] { 500, 500 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferences.getBoolean("notificationStyleLight", false)) {
|
||||||
|
builder.setLights(0xFF00FF8F, 300, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))).notify(mId, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBitmapFailed(Drawable errorDrawable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepareLoad(Drawable placeHolderDrawable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Picasso.with(this)
|
||||||
|
.load(body.account.avatar)
|
||||||
|
.placeholder(R.drawable.avatar_default)
|
||||||
|
.into(mTarget);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
builder.setVisibility(android.app.Notification.VISIBILITY_PRIVATE);
|
||||||
|
builder.setCategory(android.app.Notification.CATEGORY_SOCIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (body.type) {
|
||||||
|
case MENTION:
|
||||||
|
builder.setContentTitle(String.format(getString(R.string.notification_mention_format), body.account.getDisplayName()))
|
||||||
|
.setContentText(truncateWithEllipses(body.status.content.toString(), 40));
|
||||||
|
break;
|
||||||
|
case FOLLOW:
|
||||||
|
builder.setContentTitle(String.format(getString(R.string.notification_follow_format), body.account.getDisplayName()))
|
||||||
|
.setContentText(truncateWithEllipses(body.account.username, 40));
|
||||||
|
break;
|
||||||
|
case FAVOURITE:
|
||||||
|
builder.setContentTitle(String.format(getString(R.string.notification_favourite_format), body.account.getDisplayName()))
|
||||||
|
.setContentText(truncateWithEllipses(body.status.content.toString(), 40));
|
||||||
|
break;
|
||||||
|
case REBLOG:
|
||||||
|
builder.setContentTitle(String.format(getString(R.string.notification_reblog_format), body.account.getDisplayName()))
|
||||||
|
.setContentText(truncateWithEllipses(body.status.content.toString(), 40));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))).notify(mId, builder.build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ package com.keylesspalace.tusky;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
@ -58,9 +59,6 @@ public class NotificationsFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
NotificationManager notificationManager =
|
|
||||||
(NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
notificationManager.cancel(PullNotificationService.NOTIFY_ID);
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +117,12 @@ public class NotificationsFragment extends SFragment implements
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
sendFetchNotificationsRequest();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
TabLayout tabLayout = (TabLayout) getActivity().findViewById(R.id.tab_layout);
|
TabLayout tabLayout = (TabLayout) getActivity().findViewById(R.id.tab_layout);
|
||||||
|
@ -165,6 +169,13 @@ public class NotificationsFragment extends SFragment implements
|
||||||
if (notifications.size() > 0 && !findNotification(notifications, fromId)) {
|
if (notifications.size() > 0 && !findNotification(notifications, fromId)) {
|
||||||
setFetchTimelineState(FooterViewHolder.State.LOADING);
|
setFetchTimelineState(FooterViewHolder.State.LOADING);
|
||||||
adapter.addItems(notifications);
|
adapter.addItems(notifications);
|
||||||
|
|
||||||
|
// Set last update id for pull notifications so that we don't get notified
|
||||||
|
// about things we already loaded here
|
||||||
|
SharedPreferences preferences = getActivity().getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putString("lastUpdateId", notifications.get(0).id);
|
||||||
|
editor.apply();
|
||||||
} else {
|
} else {
|
||||||
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
|
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,233 +0,0 @@
|
||||||
/* 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
|
|
||||||
* 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
|
|
||||||
* <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
package com.keylesspalace.tusky;
|
|
||||||
|
|
||||||
import android.app.*;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.support.v4.app.TaskStackBuilder;
|
|
||||||
import android.text.Spanned;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.keylesspalace.tusky.entity.*;
|
|
||||||
import com.keylesspalace.tusky.entity.Notification;
|
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
import com.squareup.picasso.Target;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import okhttp3.Interceptor;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Retrofit;
|
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
|
||||||
|
|
||||||
public class PullNotificationService extends IntentService {
|
|
||||||
static final int NOTIFY_ID = 6; // This is an arbitrary number.
|
|
||||||
private static final String TAG = "PullNotifications"; // logging tag
|
|
||||||
|
|
||||||
public PullNotificationService() {
|
|
||||||
super("Tusky Pull Notification Service");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHandleIntent(Intent intent) {
|
|
||||||
SharedPreferences preferences = getSharedPreferences(
|
|
||||||
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
|
||||||
String domain = preferences.getString("domain", null);
|
|
||||||
String accessToken = preferences.getString("accessToken", null);
|
|
||||||
String lastUpdateId = preferences.getString("lastUpdateId", null);
|
|
||||||
checkNotifications(domain, accessToken, lastUpdateId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkNotifications(final String domain, final String accessToken,
|
|
||||||
final String lastUpdateId) {
|
|
||||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
|
||||||
.addInterceptor(new Interceptor() {
|
|
||||||
@Override
|
|
||||||
public okhttp3.Response intercept(Chain chain) throws IOException {
|
|
||||||
Request originalRequest = chain.request();
|
|
||||||
|
|
||||||
Request.Builder builder = originalRequest.newBuilder()
|
|
||||||
.header("Authorization", String.format("Bearer %s", accessToken));
|
|
||||||
|
|
||||||
Request newRequest = builder.build();
|
|
||||||
|
|
||||||
return chain.proceed(newRequest);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Gson gson = new GsonBuilder()
|
|
||||||
.registerTypeAdapter(Spanned.class, new SpannedTypeAdapter())
|
|
||||||
.create();
|
|
||||||
|
|
||||||
Retrofit retrofit = new Retrofit.Builder()
|
|
||||||
.baseUrl("https://" + domain)
|
|
||||||
.client(okHttpClient)
|
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
MastodonAPI api = retrofit.create(MastodonAPI.class);
|
|
||||||
|
|
||||||
api.notifications(null, lastUpdateId, null).enqueue(new Callback<List<Notification>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<List<Notification>> call, retrofit2.Response<List<Notification>> response) {
|
|
||||||
onCheckNotificationsSuccess(response.body(), lastUpdateId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<List<Notification>> call, Throwable t) {
|
|
||||||
onCheckNotificationsFailure((Exception) t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onCheckNotificationsSuccess(List<com.keylesspalace.tusky.entity.Notification> notifications, String lastUpdateId) {
|
|
||||||
List<MentionResult> mentions = new ArrayList<>();
|
|
||||||
|
|
||||||
for (com.keylesspalace.tusky.entity.Notification notification : notifications) {
|
|
||||||
if (notification.type == com.keylesspalace.tusky.entity.Notification.Type.MENTION) {
|
|
||||||
Status status = notification.status;
|
|
||||||
|
|
||||||
if (status != null) {
|
|
||||||
MentionResult mention = new MentionResult();
|
|
||||||
mention.content = status.content.toString();
|
|
||||||
mention.displayName = notification.account.getDisplayName();
|
|
||||||
mention.avatarUrl = status.account.avatar;
|
|
||||||
mentions.add(mention);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notifications.size() > 0) {
|
|
||||||
SharedPreferences preferences = getSharedPreferences(
|
|
||||||
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
|
||||||
editor.putString("lastUpdateId", notifications.get(0).id);
|
|
||||||
editor.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mentions.size() > 0) {
|
|
||||||
loadAvatar(mentions, mentions.get(0).avatarUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onCheckNotificationsFailure(Exception exception) {
|
|
||||||
Log.e(TAG, "Failed to check notifications. " + exception.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MentionResult {
|
|
||||||
String displayName;
|
|
||||||
String content;
|
|
||||||
String avatarUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String truncateWithEllipses(String string, int limit) {
|
|
||||||
if (string.length() < limit) {
|
|
||||||
return string;
|
|
||||||
} else {
|
|
||||||
return string.substring(0, limit - 3) + "...";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadAvatar(final List<MentionResult> mentions, String url) {
|
|
||||||
if (url != null) {
|
|
||||||
Target target = new Target() {
|
|
||||||
@Override
|
|
||||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
|
||||||
updateNotification(mentions, bitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBitmapFailed(Drawable errorDrawable) {
|
|
||||||
updateNotification(mentions, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPrepareLoad(Drawable placeHolderDrawable) {}
|
|
||||||
};
|
|
||||||
Picasso.with(this)
|
|
||||||
.load(url)
|
|
||||||
.into(target);
|
|
||||||
} else {
|
|
||||||
updateNotification(mentions, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateNotification(List<MentionResult> mentions, @Nullable Bitmap icon) {
|
|
||||||
final int NOTIFICATION_CONTENT_LIMIT = 40;
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
String title;
|
|
||||||
if (mentions.size() > 1) {
|
|
||||||
title = String.format(
|
|
||||||
getString(R.string.notification_service_several_mentions),
|
|
||||||
mentions.size());
|
|
||||||
} else {
|
|
||||||
title = String.format(
|
|
||||||
getString(R.string.notification_service_one_mention),
|
|
||||||
mentions.get(0).displayName);
|
|
||||||
}
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
|
|
||||||
.setSmallIcon(R.drawable.ic_notify)
|
|
||||||
.setContentTitle(title);
|
|
||||||
if (icon != null) {
|
|
||||||
builder.setLargeIcon(icon);
|
|
||||||
}
|
|
||||||
if (preferences.getBoolean("notificationAlertSound", true)) {
|
|
||||||
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
|
|
||||||
}
|
|
||||||
if (preferences.getBoolean("notificationStyleVibrate", false)) {
|
|
||||||
builder.setVibrate(new long[] { 500, 500 });
|
|
||||||
}
|
|
||||||
if (preferences.getBoolean("notificationStyleLight", false)) {
|
|
||||||
builder.setLights(0xFF00FF8F, 300, 1000);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < mentions.size(); i++) {
|
|
||||||
MentionResult mention = mentions.get(i);
|
|
||||||
String text = truncateWithEllipses(mention.content, NOTIFICATION_CONTENT_LIMIT);
|
|
||||||
builder.setContentText(text)
|
|
||||||
.setNumber(i);
|
|
||||||
}
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
builder.setVisibility(android.app.Notification.VISIBILITY_PRIVATE);
|
|
||||||
builder.setCategory(android.app.Notification.CATEGORY_SOCIAL);
|
|
||||||
}
|
|
||||||
Intent resultIntent = new Intent(this, SplashActivity.class);
|
|
||||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
|
|
||||||
stackBuilder.addParentStack(SplashActivity.class);
|
|
||||||
stackBuilder.addNextIntent(resultIntent);
|
|
||||||
PendingIntent resultPendingIntent =
|
|
||||||
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
builder.setContentIntent(resultPendingIntent);
|
|
||||||
NotificationManager notificationManager =
|
|
||||||
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
notificationManager.notify(NOTIFY_ID, builder.build());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -206,7 +206,6 @@ public class SFragment extends Fragment {
|
||||||
|
|
||||||
FragmentManager manager = getFragmentManager();
|
FragmentManager manager = getFragmentManager();
|
||||||
manager.beginTransaction()
|
manager.beginTransaction()
|
||||||
.setCustomAnimations(R.anim.zoom_in, R.anim.zoom_out, R.anim.zoom_in, R.anim.zoom_out)
|
|
||||||
.add(R.id.overlay_fragment_container, newFragment)
|
.add(R.id.overlay_fragment_container, newFragment)
|
||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
|
@ -22,6 +22,8 @@ import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
public class SplashActivity extends Activity {
|
public class SplashActivity extends Activity {
|
||||||
private static int SPLASH_TIME_OUT = 2000;
|
private static int SPLASH_TIME_OUT = 2000;
|
||||||
|
@ -29,7 +31,12 @@ public class SplashActivity extends Activity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
|
||||||
setContentView(R.layout.activity_splash);
|
setContentView(R.layout.activity_splash);
|
||||||
|
|
||||||
/* Determine whether the user is currently logged in, and if so go ahead and load the
|
/* Determine whether the user is currently logged in, and if so go ahead and load the
|
||||||
* timeline. Otherwise, start the activity_login screen. */
|
* timeline. Otherwise, start the activity_login screen. */
|
||||||
SharedPreferences preferences = getSharedPreferences(
|
SharedPreferences preferences = getSharedPreferences(
|
||||||
|
|
|
@ -138,6 +138,12 @@ public class TimelineFragment extends SFragment implements
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
sendFetchTimelineRequest();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
if (jumpToTopAllowed()) {
|
if (jumpToTopAllowed()) {
|
||||||
|
|
|
@ -55,6 +55,6 @@ class TimelinePagerAdapter extends FragmentPagerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getPageTitle(int position) {
|
public CharSequence getPageTitle(int position) {
|
||||||
return pageTitles[position];
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
app/src/main/java/com/keylesspalace/tusky/TuskyAPI.java
Normal file
16
app/src/main/java/com/keylesspalace/tusky/TuskyAPI.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Field;
|
||||||
|
import retrofit2.http.FormUrlEncoded;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
|
||||||
|
public interface TuskyAPI {
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/register")
|
||||||
|
Call<ResponseBody> register(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken, @Field("device_token") String deviceToken);
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/unregister")
|
||||||
|
Call<ResponseBody> unregister(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken);
|
||||||
|
}
|
|
@ -21,20 +21,30 @@ import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class ViewTagActivity extends BaseActivity {
|
public class ViewTagActivity extends BaseActivity {
|
||||||
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_view_tag);
|
setContentView(R.layout.activity_view_tag);
|
||||||
|
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
String hashtag = getIntent().getStringExtra("hashtag");
|
String hashtag = getIntent().getStringExtra("hashtag");
|
||||||
|
|
||||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
ActionBar bar = getSupportActionBar();
|
ActionBar bar = getSupportActionBar();
|
||||||
|
|
||||||
if (bar != null) {
|
if (bar != null) {
|
||||||
bar.setTitle(String.format(getString(R.string.title_tag), hashtag));
|
bar.setTitle(String.format(getString(R.string.title_tag), hashtag));
|
||||||
|
bar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
bar.setDisplayShowHomeEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||||
|
@ -42,4 +52,15 @@ public class ViewTagActivity extends BaseActivity {
|
||||||
fragmentTransaction.add(R.id.fragment_container, fragment);
|
fragmentTransaction.add(R.id.fragment_container, fragment);
|
||||||
fragmentTransaction.commit();
|
fragmentTransaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home: {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.widget.DividerItemDecoration;
|
import android.support.v7.widget.DividerItemDecoration;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
@ -63,6 +64,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
|
||||||
R.drawable.status_divider_dark);
|
R.drawable.status_divider_dark);
|
||||||
divider.setDrawable(drawable);
|
divider.setDrawable(drawable);
|
||||||
recyclerView.addItemDecoration(divider);
|
recyclerView.addItemDecoration(divider);
|
||||||
|
recyclerView.addItemDecoration(new ConversationLineItemDecoration(context, ContextCompat.getDrawable(context, R.drawable.conversation_divider_dark)));
|
||||||
adapter = new ThreadAdapter(this);
|
adapter = new ThreadAdapter(this);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
|
|
@ -16,21 +16,53 @@
|
||||||
package com.keylesspalace.tusky;
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.widget.MediaController;
|
import android.widget.MediaController;
|
||||||
import android.widget.VideoView;
|
import android.widget.VideoView;
|
||||||
|
|
||||||
public class ViewVideoActivity extends AppCompatActivity {
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class ViewVideoActivity extends BaseActivity {
|
||||||
|
@BindView(R.id.video_player) VideoView videoView;
|
||||||
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_view_video);
|
setContentView(R.layout.activity_view_video);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
ActionBar bar = getSupportActionBar();
|
||||||
|
|
||||||
|
if (bar != null) {
|
||||||
|
bar.setTitle(null);
|
||||||
|
bar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
bar.setDisplayShowHomeEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
String url = getIntent().getStringExtra("url");
|
String url = getIntent().getStringExtra("url");
|
||||||
VideoView videoView = (VideoView) findViewById(R.id.video_player);
|
|
||||||
videoView.setVideoPath(url);
|
videoView.setVideoPath(url);
|
||||||
MediaController controller = new MediaController(this);
|
MediaController controller = new MediaController(this);
|
||||||
videoView.setMediaController(controller);
|
videoView.setMediaController(controller);
|
||||||
controller.show();
|
controller.show();
|
||||||
videoView.start();
|
videoView.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home: {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
7
app/src/main/res/drawable/conversation_divider_dark.xml
Normal file
7
app/src/main/res/drawable/conversation_divider_dark.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<size android:width="2dp" />
|
||||||
|
<solid android:color="@color/color_primary_dark_dark" />
|
||||||
|
</shape>
|
9
app/src/main/res/drawable/ic_clear_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_clear_24dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/toolbar_icon_dark"
|
||||||
|
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_home_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_home_24dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/toolbar_icon_dark"
|
||||||
|
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_notifications_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_notifications_24dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/toolbar_icon_dark"
|
||||||
|
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/>
|
||||||
|
</vector>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="@color/toolbar_icon_dark"
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -25,14 +25,12 @@
|
||||||
android:id="@+id/fragment_container"
|
android:id="@+id/fragment_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/overlay_fragment_container"
|
android:id="@+id/overlay_fragment_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
|
@ -1,14 +1,24 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/view_video_background">
|
android:background="@color/view_video_background"
|
||||||
|
tools:context=".ViewVideoActivity">
|
||||||
<VideoView
|
<VideoView
|
||||||
android:id="@+id/video_player"
|
android:id="@+id/video_player"
|
||||||
|
android:layout_marginTop="?attr/actionBarSize"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerInParent="true" />
|
android:layout_centerInParent="true" />
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:theme="@style/AppTheme.Account.AppBarLayout"
|
||||||
|
app:popupTheme="@style/AppTheme.Account.ToolbarPopupTheme.Dark"
|
||||||
|
android:elevation="4dp"
|
||||||
|
android:background="@color/semi_transparent" />
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
|
@ -2,6 +2,7 @@
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:clickable="true"
|
||||||
android:background="#60000000">
|
android:background="#60000000">
|
||||||
<uk.co.senab.photoview.PhotoView
|
<uk.co.senab.photoview.PhotoView
|
||||||
android:id="@+id/view_media_image"
|
android:id="@+id/view_media_image"
|
||||||
|
|
|
@ -1,56 +1,47 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="72dp"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp"
|
android:paddingRight="16dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
android:id="@+id/account_container">
|
android:id="@+id/account_container">
|
||||||
|
|
||||||
<RelativeLayout
|
<com.pkmmte.view.CircularImageView
|
||||||
android:paddingTop="8dp"
|
android:layout_width="48dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="48dp"
|
||||||
android:layout_height="wrap_content">
|
android:layout_centerVertical="true"
|
||||||
|
android:id="@+id/account_avatar"
|
||||||
|
android:layout_marginRight="24dp" />
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:layout_width="48dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="48dp"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/account_avatar"
|
android:orientation="vertical"
|
||||||
android:layout_marginRight="10dp" />
|
android:gravity="center_vertical"
|
||||||
|
android:layout_toRightOf="@id/account_avatar">
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:id="@+id/account_display_name"
|
||||||
|
android:text="Display name"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textStyle="normal|bold" />
|
||||||
|
|
||||||
android:layout_centerVertical="true"
|
<TextView
|
||||||
android:layout_toRightOf="@id/account_avatar">
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="\@username"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:id="@+id/account_username" />
|
||||||
|
|
||||||
<TextView
|
</LinearLayout>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/account_display_name"
|
|
||||||
android:text="Display name"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textStyle="normal|bold" />
|
|
||||||
|
|
||||||
<TextView
|
</RelativeLayout>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="\@username"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
|
||||||
android:id="@+id/account_username" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/account_note"
|
|
||||||
android:paddingTop="4dp"
|
|
||||||
android:paddingBottom="8dp"
|
|
||||||
android:textColor="?android:textColorTertiary" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,60 +1,57 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="72dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<ImageView
|
<com.pkmmte.view.CircularImageView
|
||||||
android:layout_width="64dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="48dp"
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:id="@+id/blocked_user_avatar"
|
android:id="@+id/blocked_user_avatar"
|
||||||
android:padding="@dimen/status_avatar_padding"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_alignParentLeft="true" />
|
android:layout_marginRight="24dp"
|
||||||
|
android:layout_centerVertical="true"/>
|
||||||
|
|
||||||
<Button
|
<ImageButton
|
||||||
android:layout_width="wrap_content"
|
app:srcCompat="@drawable/ic_clear_24dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
android:id="@+id/blocked_user_unblock"
|
android:id="@+id/blocked_user_unblock"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:text="@string/action_unblock"
|
style="?attr/image_button_style"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
android:layout_centerVertical="true" />
|
android:layout_centerVertical="true" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="64dp"
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_toRightOf="@id/blocked_user_avatar"
|
android:layout_toRightOf="@id/blocked_user_avatar"
|
||||||
android:layout_toLeftOf="@id/blocked_user_unblock">
|
android:layout_toLeftOf="@id/blocked_user_unblock">
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/blocked_user_display_name"
|
android:id="@+id/blocked_user_display_name"
|
||||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
|
android:text="Display name"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textStyle="normal|bold" />
|
android:textStyle="normal|bold" />
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:text="\@username"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textSize="14sp"
|
||||||
android:id="@+id/blocked_user_username"
|
android:id="@+id/blocked_user_username"
|
||||||
android:textColor="?android:textColorSecondary" />
|
android:textColor="?android:textColorSecondary" />
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -20,4 +20,5 @@
|
||||||
<dimen name="account_note_margin">8dp</dimen>
|
<dimen name="account_note_margin">8dp</dimen>
|
||||||
<dimen name="account_avatar_margin">8dp</dimen>
|
<dimen name="account_avatar_margin">8dp</dimen>
|
||||||
<dimen name="tab_page_margin">8dp</dimen>
|
<dimen name="tab_page_margin">8dp</dimen>
|
||||||
|
<dimen name="status_left_line_margin">38dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<string name="title_follows">Follows</string>
|
<string name="title_follows">Follows</string>
|
||||||
<string name="title_followers">Followers</string>
|
<string name="title_followers">Followers</string>
|
||||||
<string name="title_favourites">Favourites</string>
|
<string name="title_favourites">Favourites</string>
|
||||||
<string name="title_blocks">Blocked Users</string>
|
<string name="title_blocks">Blocked users</string>
|
||||||
|
|
||||||
<string name="status_username_format">\@%s</string>
|
<string name="status_username_format">\@%s</string>
|
||||||
<string name="status_boosted_format">%s boosted</string>
|
<string name="status_boosted_format">%s boosted</string>
|
||||||
|
@ -50,8 +50,8 @@
|
||||||
<string name="footer_end_of_notifications">end of the notifications</string>
|
<string name="footer_end_of_notifications">end of the notifications</string>
|
||||||
<string name="footer_end_of_accounts">end of the accounts</string>
|
<string name="footer_end_of_accounts">end of the accounts</string>
|
||||||
|
|
||||||
<string name="notification_reblog_format">%s boosted your status</string>
|
<string name="notification_reblog_format">%s boosted your toot</string>
|
||||||
<string name="notification_favourite_format">%s favourited your status</string>
|
<string name="notification_favourite_format">%s favourited your toot</string>
|
||||||
<string name="notification_follow_format">%s followed you</string>
|
<string name="notification_follow_format">%s followed you</string>
|
||||||
|
|
||||||
<string name="report_username_format">Report @%s</string>
|
<string name="report_username_format">Report @%s</string>
|
||||||
|
@ -129,5 +129,7 @@
|
||||||
<string name="search">Search accounts…</string>
|
<string name="search">Search accounts…</string>
|
||||||
<string name="toggle_nsfw">NSFW</string>
|
<string name="toggle_nsfw">NSFW</string>
|
||||||
<string name="action_mention">Mention</string>
|
<string name="action_mention">Mention</string>
|
||||||
|
<string name="tusky_api_url">http://tusky.zeonfederated.com</string>
|
||||||
|
<string name="notification_mention_format">%s mentioned you</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -3,39 +3,20 @@
|
||||||
android:key="@string/preferences_file_key">
|
android:key="@string/preferences_file_key">
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/pref_title_notification_settings">
|
<PreferenceCategory android:title="@string/pref_title_notification_settings">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="pullNotifications"
|
|
||||||
android:title="@string/pref_title_pull_notifications"
|
|
||||||
android:summary="@string/pref_summary_pull_notifications"
|
|
||||||
android:defaultValue="true" />
|
|
||||||
|
|
||||||
<ListPreference
|
|
||||||
android:dependency="pullNotifications"
|
|
||||||
android:key="pullNotificationCheckInterval"
|
|
||||||
android:title="@string/pref_title_pull_notification_check_interval"
|
|
||||||
android:summary="@string/pref_summary_pull_notification_check_interval"
|
|
||||||
android:entries="@array/pull_notification_check_interval_names"
|
|
||||||
android:entryValues="@array/pull_notification_check_intervals"
|
|
||||||
android:defaultValue="15" />
|
|
||||||
|
|
||||||
<CheckBoxPreference
|
|
||||||
android:dependency="pullNotifications"
|
|
||||||
android:key="notificationAlertSound"
|
android:key="notificationAlertSound"
|
||||||
android:title="@string/pref_title_notification_alert_sound"
|
android:title="@string/pref_title_notification_alert_sound"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:dependency="pullNotifications"
|
|
||||||
android:key="notificationStyleVibrate"
|
android:key="notificationStyleVibrate"
|
||||||
android:title="@string/pref_title_notification_style_vibrate"
|
android:title="@string/pref_title_notification_style_vibrate"
|
||||||
android:defaultValue="false" />
|
android:defaultValue="true" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:dependency="pullNotifications"
|
|
||||||
android:key="notificationStyleLight"
|
android:key="notificationStyleLight"
|
||||||
android:title="@string/pref_title_notification_style_light"
|
android:title="@string/pref_title_notification_style_light"
|
||||||
android:defaultValue="false" />
|
android:defaultValue="true" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ buildscript {
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
classpath 'com.google.gms:google-services:3.0.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue