Merge branch 'Gargron-master'

This commit is contained in:
Vavassor 2017-03-14 18:41:07 -04:00
commit f391538984
14 changed files with 314 additions and 118 deletions

View File

@ -47,6 +47,8 @@ import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@ -63,10 +65,13 @@ public class AccountActivity extends BaseActivity {
private TabLayout tabLayout;
private Account loadedAccount;
@BindView(R.id.account_locked) ImageView accountLockedView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
ButterKnife.bind(this);
Intent intent = getIntent();
accountId = intent.getStringExtra("id");
@ -193,6 +198,12 @@ public class AccountActivity extends BaseActivity {
note.setLinksClickable(true);
note.setMovementMethod(LinkMovementMethod.getInstance());
if (account.locked) {
accountLockedView.setVisibility(View.VISIBLE);
} else {
accountLockedView.setVisibility(View.GONE);
}
Picasso.with(this)
.load(account.avatar)
.placeholder(R.drawable.avatar_default)

View File

@ -40,10 +40,13 @@ import retrofit2.Callback;
public class AccountFragment extends Fragment implements AccountActionListener {
private static final String TAG = "Account"; // logging tag
private Call<List<Account>> listCall;
public enum Type {
FOLLOWS,
FOLLOWERS,
BLOCKS,
MUTES,
}
private Type type;
@ -141,6 +144,12 @@ public class AccountFragment extends Fragment implements AccountActionListener {
return rootView;
}
@Override
public void onDestroy() {
super.onDestroy();
if (listCall != null) listCall.cancel();
}
@Override
public void onDestroyView() {
if (jumpToTopAllowed()) {
@ -166,15 +175,23 @@ public class AccountFragment extends Fragment implements AccountActionListener {
switch (type) {
default:
case FOLLOWS: {
api.accountFollowing(accountId, fromId, uptoId, null).enqueue(cb);
listCall = api.accountFollowing(accountId, fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case FOLLOWERS: {
api.accountFollowers(accountId, fromId, uptoId, null).enqueue(cb);
listCall = api.accountFollowers(accountId, fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case BLOCKS: {
api.blocks(fromId, uptoId, null).enqueue(cb);
listCall = api.blocks(fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case MUTES: {
listCall = api.mutes(fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
}

View File

@ -399,11 +399,18 @@ public class ComposeActivity extends BaseActivity {
if (intent != null) {
inReplyToId = intent.getStringExtra("in_reply_to_id");
String replyVisibility = intent.getStringExtra("reply_visibility");
if (replyVisibility != null) {
/* Override any remembered visibilty and instead adopt the visibility of the status
* to which this replies. */
// Lowest possible visibility setting in response
if (statusVisibility.equals("private") || replyVisibility.equals("private")) {
statusVisibility = "private";
} else if (statusVisibility.equals("unlisted") || replyVisibility.equals("unlisted")) {
statusVisibility = "unlisted";
} else {
statusVisibility = replyVisibility;
}
}
mentionedUsernames = intent.getStringArrayExtra("mentioned_usernames");
}

View File

@ -22,7 +22,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
@ -34,6 +33,8 @@ import com.keylesspalace.tusky.entity.AppCredentials;
import java.util.HashMap;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@ -45,10 +46,14 @@ public class LoginActivity extends BaseActivity {
private static String OAUTH_SCOPES = "read write follow";
private SharedPreferences preferences;
private String domain;
private String clientId;
private String clientSecret;
private EditText editText;
@BindView(R.id.edit_text_domain) EditText editText;
@BindView(R.id.button_login) Button button;
@BindView(R.id.no_account) TextView noAccount;
/**
* Chain together the key-value pairs into a query string, for either appending to a URL or
@ -117,6 +122,7 @@ public class LoginActivity extends BaseActivity {
* time. */
String prefClientId = preferences.getString(domain + "/client_id", null);
String prefClientSecret = preferences.getString(domain + "/client_secret", null);
if (prefClientId != null && prefClientSecret != null) {
clientId = prefClientId;
clientSecret = prefClientSecret;
@ -126,9 +132,7 @@ public class LoginActivity extends BaseActivity {
@Override
public void onResponse(Call<AppCredentials> call, Response<AppCredentials> response) {
if (!response.isSuccessful()) {
editText.setError(
"This app could not obtain authentication from that server " +
"instance.");
editText.setError(getString(R.string.error_failed_app_registration));
Log.e(TAG, "App authentication failed. " + response.message());
return;
}
@ -144,15 +148,17 @@ public class LoginActivity extends BaseActivity {
@Override
public void onFailure(Call<AppCredentials> call, Throwable t) {
editText.setError(
"This app could not obtain authentication from that server " +
"instance.");
editText.setError(getString(R.string.error_failed_app_registration));
t.printStackTrace();
}
};
try {
getApiFor(domain).authenticateApp(getString(R.string.app_name), getOauthRedirectUri(), OAUTH_SCOPES,
getString(R.string.app_website)).enqueue(callback);
} catch (IllegalArgumentException e) {
editText.setError(getString(R.string.error_invalid_domain));
}
}
}
@ -161,25 +167,26 @@ public class LoginActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
if (savedInstanceState != null) {
domain = savedInstanceState.getString("domain");
clientId = savedInstanceState.getString("clientId");
clientSecret = savedInstanceState.getString("clientSecret");
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
preferences = getSharedPreferences(
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
Button button = (Button) findViewById(R.id.button_login);
editText = (EditText) findViewById(R.id.edit_text_domain);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onButtonClick(editText);
}
});
TextView noAccount = (TextView) findViewById(R.id.no_account);
final Context context = this;
noAccount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -233,11 +240,12 @@ public class LoginActivity extends BaseActivity {
* redirect that was given to the server. If so, its response is here! */
Uri uri = getIntent().getData();
String redirectUri = getOauthRedirectUri();
if (uri != null && uri.toString().startsWith(redirectUri)) {
// This should either have returned an authorization code or an error.
String code = uri.getQueryParameter("code");
String error = uri.getQueryParameter("error");
final TextView errorText = (TextView) findViewById(R.id.text_error);
if (code != null) {
/* During the redirect roundtrip this Activity usually dies, which wipes out the
* instance variables, so they have to be recovered from where they were saved in
@ -264,15 +272,16 @@ public class LoginActivity extends BaseActivity {
editText.setError(t.getMessage());
}
};
getApiFor(domain).fetchOAuthToken(clientId, clientSecret, redirectUri, code,
"authorization_code").enqueue(callback);
} else if (error != null) {
/* Authorization failed. Put the error response where the user can read it and they
* can try again. */
errorText.setText(error);
editText.setError(error);
} else {
// This case means a junk response was received somehow.
errorText.setText(getString(R.string.error_authorization_unknown));
editText.setError(getString(R.string.error_authorization_unknown));
}
}
}

View File

@ -15,6 +15,7 @@
package com.keylesspalace.tusky;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -22,12 +23,12 @@ import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
@ -187,6 +188,18 @@ public class MainActivity extends BaseActivity {
});
}
@Override
protected void onResume() {
super.onResume();
SharedPreferences notificationPreferences = getApplicationContext().getSharedPreferences("Notifications", MODE_PRIVATE);
SharedPreferences.Editor editor = notificationPreferences.edit();
editor.putString("current", "[]");
editor.apply();
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))).cancel(MyFirebaseMessagingService.NOTIFY_ID);
}
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
ArrayList<Integer> pageHistoryList = new ArrayList<>();

View File

@ -22,6 +22,9 @@ import com.keylesspalace.tusky.entity.Notification;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.IOException;
import okhttp3.Interceptor;
@ -36,6 +39,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private MastodonAPI mastodonAPI;
private static final String TAG = "MyFirebaseMessagingService";
public static final int NOTIFY_ID = 666;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
@ -112,6 +116,34 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
private void buildNotification(Notification body) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences notificationPreferences = getApplicationContext().getSharedPreferences("Notifications", MODE_PRIVATE);
String rawCurrentNotifications = notificationPreferences.getString("current", "[]");
JSONArray currentNotifications;
try {
currentNotifications = new JSONArray(rawCurrentNotifications);
} catch (JSONException e) {
currentNotifications = new JSONArray();
}
boolean alreadyContains = false;
for(int i = 0; i < currentNotifications.length(); i++) {
try {
if (currentNotifications.getString(i).equals(body.account.displayName)) {
alreadyContains = true;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
if (!alreadyContains) currentNotifications.put(body.account.displayName);
SharedPreferences.Editor editor = notificationPreferences.edit();
editor.putString("current", currentNotifications.toString());
editor.commit();
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("tab_position", 1);
@ -122,30 +154,21 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
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);
if (currentNotifications.length() == 1) {
builder.setContentTitle(titleForType(body))
.setContentText(truncateWithEllipses(bodyForType(body), 40));
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);
}
setupPreferences(preferences, builder);
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());
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))).notify(NOTIFY_ID, builder.build());
}
@Override
@ -164,31 +187,76 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
.placeholder(R.drawable.avatar_default)
.transform(new RoundedTransformation(7, 0))
.into(mTarget);
} else {
setupPreferences(preferences, builder);
try {
builder.setContentTitle(String.format(getString(R.string.notification_title_summary), currentNotifications.length()))
.setContentText(truncateWithEllipses(joinNames(currentNotifications), 40));
} catch (JSONException e) {
e.printStackTrace();
}
}
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(NOTIFY_ID, builder.build());
}
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))).notify(mId, builder.build());
private void setupPreferences(SharedPreferences preferences, NotificationCompat.Builder builder) {
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);
}
}
private String joinNames(JSONArray array) throws JSONException {
if (array.length() > 3) {
return String.format(getString(R.string.notification_summary_large), array.get(0), array.get(1), array.get(2), array.length() - 3);
} else if (array.length() == 3) {
return String.format(getString(R.string.notification_summary_medium), array.get(0), array.get(1), array.get(2));
} else if (array.length() == 2) {
return String.format(getString(R.string.notification_summary_small), array.get(0), array.get(1));
}
return null;
}
private String titleForType(Notification notification) {
switch (notification.type) {
case MENTION:
return String.format(getString(R.string.notification_mention_format), notification.account.getDisplayName());
case FOLLOW:
return String.format(getString(R.string.notification_follow_format), notification.account.getDisplayName());
case FAVOURITE:
return String.format(getString(R.string.notification_favourite_format), notification.account.getDisplayName());
case REBLOG:
return String.format(getString(R.string.notification_reblog_format), notification.account.getDisplayName());
}
return null;
}
private String bodyForType(Notification notification) {
switch (notification.type) {
case FOLLOW:
return notification.account.username;
case MENTION:
case FAVOURITE:
case REBLOG:
return notification.status.content.toString();
}
return null;
}
}

View File

@ -48,6 +48,7 @@ public class NotificationsFragment extends SFragment implements
private EndlessOnScrollListener scrollListener;
private NotificationsAdapter adapter;
private TabLayout.OnTabSelectedListener onTabSelectedListener;
private Call<List<Notification>> listCall;
public static NotificationsFragment newInstance() {
NotificationsFragment fragment = new NotificationsFragment();
@ -122,6 +123,12 @@ public class NotificationsFragment extends SFragment implements
sendFetchNotificationsRequest();
}
@Override
public void onDestroy() {
super.onDestroy();
if (listCall != null) listCall.cancel();
}
@Override
public void onDestroyView() {
TabLayout tabLayout = (TabLayout) getActivity().findViewById(R.id.tab_layout);
@ -137,7 +144,9 @@ public class NotificationsFragment extends SFragment implements
private void sendFetchNotificationsRequest(final String fromId, String uptoId) {
MastodonAPI api = ((BaseActivity) getActivity()).mastodonAPI;
api.notifications(fromId, uptoId, null).enqueue(new Callback<List<Notification>>() {
listCall = api.notifications(fromId, uptoId, null);
listCall.enqueue(new Callback<List<Notification>>() {
@Override
public void onResponse(Call<List<Notification>> call, retrofit2.Response<List<Notification>> response) {
if (response.isSuccessful()) {

View File

@ -20,8 +20,9 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.text.Spanned;
@ -47,7 +48,6 @@ import retrofit2.Callback;
public class SFragment extends Fragment {
protected String loggedInAccountId;
protected String loggedInUsername;
private MastodonAPI api;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@ -57,7 +57,10 @@ public class SFragment extends Fragment {
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
loggedInAccountId = preferences.getString("loggedInAccountId", null);
loggedInUsername = preferences.getString("loggedInAccountUsername", null);
api = ((BaseActivity) getActivity()).mastodonAPI;
}
public MastodonAPI getApi() {
return ((BaseActivity) getActivity()).mastodonAPI;
}
protected void reply(Status status) {
@ -85,6 +88,11 @@ public class SFragment extends Fragment {
public void onResponse(Call<Status> call, retrofit2.Response<Status> response) {
if (response.isSuccessful()) {
status.reblogged = reblog;
if (status.reblog != null) {
status.reblog.reblogged = reblog;
}
adapter.notifyItemChanged(position);
}
}
@ -96,9 +104,9 @@ public class SFragment extends Fragment {
};
if (reblog) {
api.reblogStatus(id).enqueue(cb);
getApi().reblogStatus(id).enqueue(cb);
} else {
api.unreblogStatus(id).enqueue(cb);
getApi().unreblogStatus(id).enqueue(cb);
}
}
@ -111,6 +119,11 @@ public class SFragment extends Fragment {
public void onResponse(Call<Status> call, retrofit2.Response<Status> response) {
if (response.isSuccessful()) {
status.favourited = favourite;
if (status.reblog != null) {
status.reblog.favourited = favourite;
}
adapter.notifyItemChanged(position);
}
}
@ -122,14 +135,14 @@ public class SFragment extends Fragment {
};
if (favourite) {
api.favouriteStatus(id).enqueue(cb);
getApi().favouriteStatus(id).enqueue(cb);
} else {
api.unfavouriteStatus(id).enqueue(cb);
getApi().unfavouriteStatus(id).enqueue(cb);
}
}
private void block(String id) {
api.blockAccount(id).enqueue(new Callback<Relationship>() {
getApi().blockAccount(id).enqueue(new Callback<Relationship>() {
@Override
public void onResponse(Call<Relationship> call, retrofit2.Response<Relationship> response) {
@ -143,7 +156,7 @@ public class SFragment extends Fragment {
}
private void delete(String id) {
api.deleteStatus(id).enqueue(new Callback<ResponseBody>() {
getApi().deleteStatus(id).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
@ -206,13 +219,9 @@ public class SFragment extends Fragment {
protected void viewMedia(String url, Status.MediaAttachment.Type type) {
switch (type) {
case IMAGE: {
Fragment newFragment = ViewMediaFragment.newInstance(url);
FragmentManager manager = getFragmentManager();
manager.beginTransaction()
.add(R.id.overlay_fragment_container, newFragment)
.addToBackStack(null)
.commit();
DialogFragment newFragment = ViewMediaFragment.newInstance(url);
FragmentTransaction ft = getFragmentManager().beginTransaction();
newFragment.show(ft, "view_media");
break;
}
case GIFV:

View File

@ -39,6 +39,8 @@ public class TimelineFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener {
private static final String TAG = "Timeline"; // logging tag
private Call<List<Status>> listCall;
enum Kind {
HOME,
PUBLIC,
@ -144,6 +146,12 @@ public class TimelineFragment extends SFragment implements
sendFetchTimelineRequest();
}
@Override
public void onDestroy() {
super.onDestroy();
if (listCall != null) listCall.cancel();
}
@Override
public void onDestroyView() {
if (jumpToTopAllowed()) {
@ -184,23 +192,28 @@ public class TimelineFragment extends SFragment implements
switch (kind) {
default:
case HOME: {
api.homeTimeline(fromId, uptoId, null).enqueue(cb);
listCall = api.homeTimeline(fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case PUBLIC: {
api.publicTimeline(null, fromId, uptoId, null).enqueue(cb);
listCall = api.publicTimeline(null, fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case TAG: {
api.hashtagTimeline(hashtagOrId, null, fromId, uptoId, null).enqueue(cb);
listCall = api.hashtagTimeline(hashtagOrId, null, fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case USER: {
api.accountStatuses(hashtagOrId, fromId, uptoId, null).enqueue(cb);
listCall = api.accountStatuses(hashtagOrId, fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
case FAVOURITES: {
api.favourites(fromId, uptoId, null).enqueue(cb);
listCall = api.favourites(fromId, uptoId, null);
listCall.enqueue(cb);
break;
}
}

View File

@ -16,21 +16,27 @@
package com.keylesspalace.tusky;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import butterknife.BindView;
import butterknife.ButterKnife;
import uk.co.senab.photoview.PhotoView;
import uk.co.senab.photoview.PhotoViewAttacher;
public class ViewMediaFragment extends Fragment {
public class ViewMediaFragment extends DialogFragment {
private PhotoViewAttacher attacher;
@BindView(R.id.view_media_image) PhotoView photoView;
public static ViewMediaFragment newInstance(String url) {
Bundle arguments = new Bundle();
ViewMediaFragment fragment = new ViewMediaFragment();
@ -39,14 +45,29 @@ public class ViewMediaFragment extends Fragment {
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.Dialog_FullScreen);
}
@Override
public void onResume() {
ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
getDialog().getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
super.onResume();
}
@Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_view_media, container, false);
ButterKnife.bind(this, rootView);
Bundle arguments = getArguments();
String url = arguments.getString("url");
PhotoView photoView = (PhotoView) rootView.findViewById(R.id.view_media_image);
attacher = new PhotoViewAttacher(photoView);
@ -84,8 +105,4 @@ public class ViewMediaFragment extends Fragment {
attacher.cleanup();
super.onDestroyView();
}
private void dismiss() {
getFragmentManager().popBackStack();
}
}

View File

@ -78,6 +78,9 @@
android:textColor="?android:textColorPrimary"
android:textSize="18sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -86,6 +89,19 @@
android:textColor="?android:textColorSecondary"
android:id="@+id/account_username" />
<ImageView
android:id="@+id/account_locked"
android:visibility="gone"
android:layout_centerVertical="true"
android:layout_width="16sp"
android:layout_height="16sp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_toEndOf="@id/account_username"
app:srcCompat="@drawable/reblog_disabled_light"
android:tint="?android:textColorSecondary"
android:layout_toRightOf="@id/account_username" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:background="#60000000">
android:layout_gravity="center"
android:background="@android:color/black">
<uk.co.senab.photoview.PhotoView
android:id="@+id/view_media_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</FrameLayout>

View File

@ -102,12 +102,8 @@
<string name="visibility_unlisted">Everyone can see, but not on public timelines</string>
<string name="visibility_private">Only followers and mentions can see</string>
<string name="notification_service_description">Allows Tusky to check for Mastodon notifications.</string>
<string name="notification_service_several_mentions">%d new mentions</string>
<string name="notification_service_one_mention">Mention from %s</string>
<string name="pref_title_notification_settings">Notifications</string>
<string name="pref_title_pull_notifications">Enable pull notifcations</string>
<string name="pref_title_pull_notifications">Enable pull notifications</string>
<string name="pref_summary_pull_notifications">Check for notifications periodically</string>
<string name="pref_title_pull_notification_check_interval">Check interval</string>
<string name="pref_summary_pull_notification_check_interval">How often to pull</string>
@ -131,5 +127,10 @@
<string name="action_mention">Mention</string>
<string name="tusky_api_url">https://tuskynotifier.keylesspalace.com</string>
<string name="notification_mention_format">%s mentioned you</string>
<string name="error_invalid_domain">Invalid domain entered</string>
<string name="error_failed_app_registration">This app could not obtain authentication from that server instance.</string>
<string name="notification_summary_large">%1$s, %2$s, %3$s and %4$d others</string>
<string name="notification_summary_medium">%1$s, %2$s, and %3$s</string>
<string name="notification_summary_small">%1$s and %2$s</string>
<string name="notification_title_summary">%d new interactions</string>
</resources>

View File

@ -92,6 +92,11 @@
<item name="windowActionBarOverlay">true</item>
</style>
<style name="Dialog.FullScreen" parent="Theme.AppCompat.Dialog">
<item name="android:padding">0dp</item>
<item name="android:windowBackground">@android:color/black</item>
</style>
<!--Light Application Theme Styles-->
<style name="AppTheme.Light" parent="Theme.AppCompat.Light.NoActionBar">