Merge branch 'master' into edit-profile

This commit is contained in:
Vavassor 2017-04-17 01:10:20 -04:00
commit e15f1cfcab
21 changed files with 648 additions and 89 deletions

View file

@ -101,6 +101,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private static final int MEDIA_PICK_RESULT = 1; private static final int MEDIA_PICK_RESULT = 1;
private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1; private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;
private static final int MEDIA_SIZE_UNKNOWN = -1; private static final int MEDIA_SIZE_UNKNOWN = -1;
private static final int COMPOSE_SUCCESS = -1;
private String inReplyToId; private String inReplyToId;
private EditText textEditor; private EditText textEditor;
@ -122,6 +123,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private ImageButton pickBtn; private ImageButton pickBtn;
private Button nsfwBtn; private Button nsfwBtn;
private ProgressBar postProgress; private ProgressBar postProgress;
private ImageButton visibilityBtn;
private static class QueuedMedia { private static class QueuedMedia {
enum Type { enum Type {
@ -341,17 +343,11 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
floatingBtn = (Button) findViewById(R.id.floating_btn); floatingBtn = (Button) findViewById(R.id.floating_btn);
pickBtn = (ImageButton) findViewById(R.id.compose_photo_pick); pickBtn = (ImageButton) findViewById(R.id.compose_photo_pick);
nsfwBtn = (Button) findViewById(R.id.action_toggle_nsfw); nsfwBtn = (Button) findViewById(R.id.action_toggle_nsfw);
final ImageButton visibilityBtn = (ImageButton) findViewById(R.id.action_toggle_visibility); visibilityBtn = (ImageButton) findViewById(R.id.action_toggle_visibility);
floatingBtn.setOnClickListener(new View.OnClickListener() { floatingBtn.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
pickBtn.setClickable(false);
nsfwBtn.setClickable(false);
visibilityBtn.setClickable(false);
floatingBtn.setEnabled(false);
postProgress.setVisibility(View.VISIBLE);
sendStatus(); sendStatus();
} }
}); });
@ -567,6 +563,20 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
} }
private void disableButtons() {
pickBtn.setClickable(false);
nsfwBtn.setClickable(false);
visibilityBtn.setClickable(false);
floatingBtn.setEnabled(false);
}
private void enableButtons() {
pickBtn.setClickable(true);
nsfwBtn.setClickable(true);
visibilityBtn.setClickable(true);
floatingBtn.setEnabled(true);
}
private void setStatusVisibility(String visibility) { private void setStatusVisibility(String visibility) {
statusVisibility = visibility; statusVisibility = visibility;
switch (visibility) { switch (visibility) {
@ -615,6 +625,18 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
updateVisibleCharactersLeft(); updateVisibleCharactersLeft();
} }
void setStateToReadying() {
statusAlreadyInFlight = true;
disableButtons();
postProgress.setVisibility(View.VISIBLE);
}
void setStateToNotReadying() {
postProgress.setVisibility(View.INVISIBLE);
statusAlreadyInFlight = false;
enableButtons();
}
private void sendStatus() { private void sendStatus() {
if (statusAlreadyInFlight) { if (statusAlreadyInFlight) {
return; return;
@ -624,9 +646,12 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
if (statusHideText) { if (statusHideText) {
spoilerText = contentWarningEditor.getText().toString(); spoilerText = contentWarningEditor.getText().toString();
} }
if (contentText.length() + spoilerText.length() <= STATUS_CHARACTER_LIMIT) { int characterCount = contentText.length() + spoilerText.length();
statusAlreadyInFlight = true; if (characterCount > 0 && characterCount <= STATUS_CHARACTER_LIMIT) {
setStateToReadying();
readyStatus(contentText, statusVisibility, statusMarkSensitive, spoilerText); readyStatus(contentText, statusVisibility, statusMarkSensitive, spoilerText);
} else if (characterCount <= 0) {
textEditor.setError(getString(R.string.error_empty));
} else { } else {
textEditor.setError(getString(R.string.error_compose_character_limit)); textEditor.setError(getString(R.string.error_compose_character_limit));
} }
@ -816,13 +841,13 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private void onSendSuccess() { private void onSendSuccess() {
Snackbar bar = Snackbar.make(findViewById(R.id.activity_compose), getString(R.string.confirmation_send), Snackbar.LENGTH_SHORT); Snackbar bar = Snackbar.make(findViewById(R.id.activity_compose), getString(R.string.confirmation_send), Snackbar.LENGTH_SHORT);
bar.show(); bar.show();
setResult(COMPOSE_SUCCESS);
finish(); finish();
} }
private void onSendFailure() { private void onSendFailure() {
postProgress.setVisibility(View.INVISIBLE);
textEditor.setError(getString(R.string.error_generic)); textEditor.setError(getString(R.string.error_generic));
statusAlreadyInFlight = false; setStateToNotReadying();
} }
private void readyStatus(final String content, final String visibility, final boolean sensitive, private void readyStatus(final String content, final String visibility, final boolean sensitive,
@ -857,7 +882,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
@Override @Override
protected void onCancelled() { protected void onCancelled() {
removeAllMediaFromQueue(); removeAllMediaFromQueue();
statusAlreadyInFlight = false; setStateToNotReadying();
super.onCancelled(); super.onCancelled();
} }
}; };
@ -882,7 +907,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
readyStatus(content, visibility, sensitive, spoilerText); readyStatus(content, visibility, sensitive, spoilerText);
} }
}); });
statusAlreadyInFlight = false; setStateToNotReadying();
} }
private void onMediaPick() { private void onMediaPick() {

View file

@ -23,6 +23,8 @@ class FooterViewHolder extends RecyclerView.ViewHolder {
FooterViewHolder(View itemView) { FooterViewHolder(View itemView) {
super(itemView); super(itemView);
ProgressBar progressBar = (ProgressBar) itemView.findViewById(R.id.footer_progress_bar); ProgressBar progressBar = (ProgressBar) itemView.findViewById(R.id.footer_progress_bar);
progressBar.setIndeterminate(true); if (progressBar != null) {
progressBar.setIndeterminate(true);
}
} }
} }

View file

@ -66,6 +66,7 @@ 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
protected static int COMPOSE_RESULT = 1;
private String loggedInAccountId; private String loggedInAccountId;
private String loggedInAccountUsername; private String loggedInAccountUsername;
@ -99,7 +100,7 @@ public class MainActivity extends BaseActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), ComposeActivity.class); Intent intent = new Intent(getApplicationContext(), ComposeActivity.class);
startActivity(intent); startActivityForResult(intent, COMPOSE_RESULT);
} }
}); });
@ -471,6 +472,17 @@ public class MainActivity extends BaseActivity {
Log.e(TAG, "Failed to fetch user info. " + exception.getMessage()); Log.e(TAG, "Failed to fetch user info. " + exception.getMessage());
} }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == COMPOSE_RESULT && resultCode == ComposeActivity.RESULT_OK) {
TimelinePagerAdapter adapter = (TimelinePagerAdapter) viewPager.getAdapter();
if (adapter.getCurrentFragment() instanceof SFragment) {
((SFragment) adapter.getCurrentFragment()).onSuccessfulStatus();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if(drawer != null && drawer.isDrawerOpen()) { if(drawer != null && drawer.isDrawerOpen()) {

View file

@ -42,9 +42,16 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
private static final int VIEW_TYPE_STATUS_NOTIFICATION = 2; private static final int VIEW_TYPE_STATUS_NOTIFICATION = 2;
private static final int VIEW_TYPE_FOLLOW = 3; private static final int VIEW_TYPE_FOLLOW = 3;
enum FooterState {
EMPTY,
END,
LOADING
}
private List<Notification> notifications; private List<Notification> notifications;
private StatusActionListener statusListener; private StatusActionListener statusListener;
private NotificationActionListener notificationActionListener; private NotificationActionListener notificationActionListener;
private FooterState footerState = FooterState.END;
NotificationsAdapter(StatusActionListener statusListener, NotificationsAdapter(StatusActionListener statusListener,
NotificationActionListener notificationActionListener) { NotificationActionListener notificationActionListener) {
@ -54,6 +61,15 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
this.notificationActionListener = notificationActionListener; this.notificationActionListener = notificationActionListener;
} }
public void setFooterState(FooterState newFooterState) {
FooterState oldValue = footerState;
footerState = newFooterState;
if (footerState != oldValue) {
notifyItemChanged(notifications.size());
}
}
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) { switch (viewType) {
@ -64,8 +80,24 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
return new StatusViewHolder(view); return new StatusViewHolder(view);
} }
case VIEW_TYPE_FOOTER: { case VIEW_TYPE_FOOTER: {
View view = LayoutInflater.from(parent.getContext()) View view;
.inflate(R.layout.item_footer, parent, false); switch (footerState) {
default:
case LOADING:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_footer, parent, false);
break;
case END: {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_footer_end, parent, false);
break;
}
case EMPTY: {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_footer_empty, parent, false);
break;
}
}
return new FooterViewHolder(view); return new FooterViewHolder(view);
} }
case VIEW_TYPE_STATUS_NOTIFICATION: { case VIEW_TYPE_STATUS_NOTIFICATION: {

View file

@ -144,6 +144,10 @@ public class NotificationsFragment extends SFragment implements
private void sendFetchNotificationsRequest(final String fromId, String uptoId) { private void sendFetchNotificationsRequest(final String fromId, String uptoId) {
MastodonAPI api = ((BaseActivity) getActivity()).mastodonAPI; MastodonAPI api = ((BaseActivity) getActivity()).mastodonAPI;
if (fromId != null || adapter.getItemCount() <= 1) {
adapter.setFooterState(NotificationsAdapter.FooterState.LOADING);
}
listCall = api.notifications(fromId, uptoId, null); listCall = api.notifications(fromId, uptoId, null);
listCall.enqueue(new Callback<List<Notification>>() { listCall.enqueue(new Callback<List<Notification>>() {
@ -192,6 +196,11 @@ public class NotificationsFragment extends SFragment implements
} else { } else {
adapter.update(notifications); adapter.update(notifications);
} }
if (notifications.size() == 0 && adapter.getItemCount() == 1) {
adapter.setFooterState(NotificationsAdapter.FooterState.EMPTY);
} else if (fromId != null) {
adapter.setFooterState(NotificationsAdapter.FooterState.END);
}
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }

View file

@ -44,9 +44,10 @@ import retrofit2.Callback;
* adapters. I feel like the profile pages and thread viewer, which I haven't made yet, will also * adapters. I feel like the profile pages and thread viewer, which I haven't made yet, will also
* overlap functionality. So, I'm momentarily leaving it and hopefully working on those will clear * overlap functionality. So, I'm momentarily leaving it and hopefully working on those will clear
* up what needs to be where. */ * up what needs to be where. */
public class SFragment extends BaseFragment { public abstract class SFragment extends BaseFragment {
protected String loggedInAccountId; protected String loggedInAccountId;
protected String loggedInUsername; protected String loggedInUsername;
protected static int COMPOSE_RESULT = 1;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
@ -79,11 +80,23 @@ public class SFragment extends BaseFragment {
intent.putExtra("reply_visibility", replyVisibility); intent.putExtra("reply_visibility", replyVisibility);
intent.putExtra("content_warning", contentWarning); intent.putExtra("content_warning", contentWarning);
intent.putExtra("mentioned_usernames", mentionedUsernames.toArray(new String[0])); intent.putExtra("mentioned_usernames", mentionedUsernames.toArray(new String[0]));
startActivity(intent); startActivityForResult(intent, COMPOSE_RESULT);
}
public void onSuccessfulStatus() {
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == COMPOSE_RESULT && resultCode == ComposeActivity.RESULT_OK) {
onSuccessfulStatus();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
} }
protected void reblog(final Status status, final boolean reblog, protected void reblog(final Status status, final boolean reblog,
final RecyclerView.Adapter adapter, final int position) { final RecyclerView.Adapter adapter, final int position) {
String id = status.getActionableId(); String id = status.getActionableId();
Callback<Status> cb = new Callback<Status>() { Callback<Status> cb = new Callback<Status>() {
@ -182,8 +195,8 @@ public class SFragment extends BaseFragment {
callList.add(call); callList.add(call);
} }
protected void more(Status status, View view, final AdapterItemRemover adapter, protected void more(final Status status, View view, final AdapterItemRemover adapter,
final int position) { final int position) {
final String id = status.getActionableId(); final String id = status.getActionableId();
final String accountId = status.getActionableStatus().account.id; final String accountId = status.getActionableStatus().account.id;
final String accountUsename = status.getActionableStatus().account.username; final String accountUsename = status.getActionableStatus().account.username;
@ -201,12 +214,25 @@ public class SFragment extends BaseFragment {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.status_share: { case R.id.status_share_content: {
StringBuilder sb = new StringBuilder();
sb.append(status.account.username);
sb.append(" - ");
sb.append(status.content.toString());
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_status_content_to)));
return true;
}
case R.id.status_share_link: {
Intent sendIntent = new Intent(); Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND); sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, statusUrl); sendIntent.putExtra(Intent.EXTRA_TEXT, statusUrl);
sendIntent.setType("text/plain"); sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_status_to))); startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_status_link_to)));
return true; return true;
} }
case R.id.status_block: { case R.id.status_block: {

View file

@ -65,20 +65,43 @@ class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
notifyItemRemoved(position); notifyItemRemoved(position);
} }
int insertStatus(Status status) { int setStatus(Status status) {
if (statuses.size() > 0 && statuses.get(statusIndex).equals(status)) {
// Do not add this status on refresh, it's already in there.
statuses.set(statusIndex, status);
return statusIndex;
}
int i = statusIndex; int i = statusIndex;
statuses.add(i, status); statuses.add(i, status);
notifyItemInserted(i); notifyItemInserted(i);
return i; return i;
} }
void addAncestors(List<Status> ancestors) { void setContext(List<Status> ancestors, List<Status> descendants) {
Status mainStatus = null;
// In case of refresh, remove old ancestors and descendants first. We'll remove all blindly,
// as we have no guarantee on their order to be the same as before
int old_size = statuses.size();
if (old_size > 0) {
mainStatus = statuses.get(statusIndex);
statuses.clear();
notifyItemRangeRemoved(0, old_size);
}
// Insert newly fetched ancestors
statusIndex = ancestors.size(); statusIndex = ancestors.size();
statuses.addAll(0, ancestors); statuses.addAll(0, ancestors);
notifyItemRangeInserted(0, statusIndex); notifyItemRangeInserted(0, statusIndex);
}
void addDescendants(List<Status> descendants) { if (mainStatus != null) {
// In case we needed to delete everything (which is way easier than deleting
// everything except one), re-insert the remaining status here.
statuses.add(statusIndex, mainStatus);
notifyItemInserted(statusIndex);
}
// Insert newly fetched descendants
int end = statuses.size(); int end = statuses.size();
statuses.addAll(descendants); statuses.addAll(descendants);
notifyItemRangeInserted(end, descendants.size()); notifyItemRangeInserted(end, descendants.size());

View file

@ -30,8 +30,15 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
private static final int VIEW_TYPE_STATUS = 0; private static final int VIEW_TYPE_STATUS = 0;
private static final int VIEW_TYPE_FOOTER = 1; private static final int VIEW_TYPE_FOOTER = 1;
enum FooterState {
EMPTY,
END,
LOADING
}
private List<Status> statuses; private List<Status> statuses;
private StatusActionListener statusListener; private StatusActionListener statusListener;
private FooterState footerState = FooterState.END;
TimelineAdapter(StatusActionListener statusListener) { TimelineAdapter(StatusActionListener statusListener) {
super(); super();
@ -49,13 +56,37 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
return new StatusViewHolder(view); return new StatusViewHolder(view);
} }
case VIEW_TYPE_FOOTER: { case VIEW_TYPE_FOOTER: {
View view = LayoutInflater.from(viewGroup.getContext()) View view;
.inflate(R.layout.item_footer, viewGroup, false); switch (footerState) {
default:
case LOADING:
view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_footer, viewGroup, false);
break;
case END: {
view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_footer_end, viewGroup, false);
break;
}
case EMPTY: {
view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_footer_empty, viewGroup, false);
break;
}
}
return new FooterViewHolder(view); return new FooterViewHolder(view);
} }
} }
} }
public void setFooterState(FooterState newFooterState) {
FooterState oldValue = footerState;
footerState = newFooterState;
if (footerState != oldValue) {
notifyItemChanged(statuses.size());
}
}
@Override @Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (position < statuses.size()) { if (position < statuses.size()) {

View file

@ -214,6 +214,10 @@ public class TimelineFragment extends SFragment implements
private void sendFetchTimelineRequest(@Nullable final String fromId, @Nullable String uptoId) { private void sendFetchTimelineRequest(@Nullable final String fromId, @Nullable String uptoId) {
MastodonAPI api = ((BaseActivity) getActivity()).mastodonAPI; MastodonAPI api = ((BaseActivity) getActivity()).mastodonAPI;
if (fromId != null || adapter.getItemCount() <= 1) {
adapter.setFooterState(TimelineAdapter.FooterState.LOADING);
}
Callback<List<Status>> cb = new Callback<List<Status>>() { Callback<List<Status>> cb = new Callback<List<Status>>() {
@Override @Override
public void onResponse(Call<List<Status>> call, retrofit2.Response<List<Status>> response) { public void onResponse(Call<List<Status>> call, retrofit2.Response<List<Status>> response) {
@ -282,6 +286,11 @@ public class TimelineFragment extends SFragment implements
} else { } else {
adapter.update(statuses); adapter.update(statuses);
} }
if (statuses.size() == 0 && adapter.getItemCount() == 1) {
adapter.setFooterState(TimelineAdapter.FooterState.EMPTY);
} else if(fromId != null) {
adapter.setFooterState(TimelineAdapter.FooterState.END);
}
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
@ -299,6 +308,14 @@ public class TimelineFragment extends SFragment implements
} }
} }
@Override
public void onSuccessfulStatus() {
if (kind == Kind.HOME || kind == Kind.PUBLIC_FEDERATED || kind == Kind.PUBLIC_LOCAL) {
onRefresh();
}
super.onSuccessfulStatus();
}
public void onReply(int position) { public void onReply(int position) {
super.reply(adapter.getItem(position)); super.reply(adapter.getItem(position));
} }

View file

@ -18,12 +18,27 @@ package com.keylesspalace.tusky;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentPagerAdapter;
import android.view.ViewGroup;
class TimelinePagerAdapter extends FragmentPagerAdapter { class TimelinePagerAdapter extends FragmentPagerAdapter {
private Fragment currentFragment;
TimelinePagerAdapter(FragmentManager manager) { TimelinePagerAdapter(FragmentManager manager) {
super(manager); super(manager);
} }
public Fragment getCurrentFragment() {
return currentFragment;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
currentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
@Override @Override
public Fragment getItem(int i) { public Fragment getItem(int i) {
switch (i) { switch (i) {

View file

@ -21,6 +21,7 @@ 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.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
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;
@ -34,9 +35,11 @@ import com.keylesspalace.tusky.entity.StatusContext;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
public class ViewThreadFragment extends SFragment implements StatusActionListener { public class ViewThreadFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener {
private static final String TAG = "ViewThreadFragment"; private static final String TAG = "ViewThreadFragment";
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerView; private RecyclerView recyclerView;
private ThreadAdapter adapter; private ThreadAdapter adapter;
private String thisThreadsStatusId; private String thisThreadsStatusId;
@ -56,6 +59,9 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false); View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false);
Context context = getContext(); Context context = getContext();
swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_refresh_layout);
swipeRefreshLayout.setOnRefreshListener(this);
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view); recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(context); LinearLayoutManager layoutManager = new LinearLayoutManager(context);
@ -86,7 +92,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
@Override @Override
public void onResponse(Call<Status> call, retrofit2.Response<Status> response) { public void onResponse(Call<Status> call, retrofit2.Response<Status> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
int position = adapter.insertStatus(response.body()); int position = adapter.setStatus(response.body());
recyclerView.scrollToPosition(position); recyclerView.scrollToPosition(position);
} else { } else {
onThreadRequestFailure(id); onThreadRequestFailure(id);
@ -109,10 +115,10 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
@Override @Override
public void onResponse(Call<StatusContext> call, retrofit2.Response<StatusContext> response) { public void onResponse(Call<StatusContext> call, retrofit2.Response<StatusContext> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
swipeRefreshLayout.setRefreshing(false);
StatusContext context = response.body(); StatusContext context = response.body();
adapter.addAncestors(context.ancestors); adapter.setContext(context.ancestors, context.descendants);
adapter.addDescendants(context.descendants);
} else { } else {
onThreadRequestFailure(id); onThreadRequestFailure(id);
} }
@ -128,6 +134,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
private void onThreadRequestFailure(final String id) { private void onThreadRequestFailure(final String id) {
View view = getView(); View view = getView();
swipeRefreshLayout.setRefreshing(false);
if (view != null) { if (view != null) {
Snackbar.make(view, R.string.error_generic, Snackbar.LENGTH_LONG) Snackbar.make(view, R.string.error_generic, Snackbar.LENGTH_LONG)
.setAction(R.string.action_retry, new View.OnClickListener() { .setAction(R.string.action_retry, new View.OnClickListener() {
@ -143,6 +150,17 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
} }
} }
public void onRefresh() {
sendStatusRequest(thisThreadsStatusId);
sendThreadRequest(thisThreadsStatusId);
}
@Override
public void onSuccessfulStatus() {
onRefresh();
super.onSuccessfulStatus();
}
public void onReply(int position) { public void onReply(int position) {
super.reply(adapter.getItem(position)); super.reply(adapter.getItem(position));
} }

View file

@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView <android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view" android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:scrollbars="vertical" /> <android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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_height="match_parent"
android:padding="16dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srcCompat="@drawable/elephant_friend" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/footer_empty"
android:textAlignment="center" />
</LinearLayout>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
</LinearLayout>

View file

@ -9,6 +9,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/title" android:id="@+id/title"
android:layout_marginTop="8dp"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:textAllCaps="true" android:textAllCaps="true"
android:textStyle="normal|bold" /> android:textStyle="normal|bold" />

View file

@ -2,7 +2,16 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/status_share" android:id="@+id/status_share"
android:title="@string/action_share"/> android:title="@string/action_share">
<menu>
<item
android:id="@+id/status_share_link"
android:title="@string/status_share_link" />
<item
android:id="@+id/status_share_content"
android:title="@string/status_share_content"/>
</menu>
</item>
<item android:title="@string/action_block" <item android:title="@string/action_block"
android:id="@+id/status_block" /> android:id="@+id/status_block" />
<item android:title="@string/action_report" <item android:title="@string/action_report"

View file

@ -0,0 +1,121 @@
<resources>
<string name="error_generic">وقع هناك خطأ.</string>
<string name="error_invalid_domain">اسم النطاق غير صالح</string>
<string name="error_failed_app_registration">اخفقت المصادقة مع مثيل الخادم هذا.</string>
<string name="error_no_web_browser_found">لم يتم العثور على متصفح قابل للإستعمال.</string>
<string name="error_authorization_denied">تم رفض التصريح.</string>
<string name="error_media_upload_size">يجب أن يكون حجم الملف أقل من 4 ميغابايت.</string>
<string name="error_media_upload_type">لا يمكن رفع هذا النوع من الملفات.</string>
<string name="error_media_upload_opening">تعذر فتح ذاك الملف.</string>
<string name="error_media_upload_sending">اخفقت عملية الرفع.</string>
<string name="title_home">الرئيسية</string>
<string name="title_notifications">الاشعارات</string>
<string name="title_public_local">المحلية</string>
<string name="title_public_federated">الفدرالية</string>
<string name="title_thread">الخيط</string>
<string name="title_tag">#%s</string>
<string name="title_statuses">المشاركات</string>
<string name="title_follows">يتبع</string>
<string name="title_followers">المتابعون</string>
<string name="title_favourites">المفضلة</string>
<string name="title_blocks">المستخدمون المحظورون</string>
<string name="status_username_format">\@%s</string>
<string name="status_boosted_format">%s عزز</string>
<string name="status_sensitive_media_title">محتوى حساس</string>
<string name="status_sensitive_media_directions">اضغط للعرض</string>
<string name="status_content_warning_show_more">اعرض أكثر</string>
<string name="status_content_warning_show_less">اعرض أقل</string>
<string name="footer_end_of_statuses">نهاية الحالات</string>
<string name="footer_end_of_notifications">نهاية الاشعارات</string>
<string name="footer_end_of_accounts">نهاية الحسابات</string>
<string name="notification_reblog_format">%s عزز تبويقك</string>
<string name="notification_favourite_format">%s أعجب بتبويقك</string>
<string name="notification_follow_format">%s يتبعك</string>
<string name="report_username_format">أبلغ عن @%s</string>
<string name="report_comment_hint">تعليقات إضافية ؟</string>
<string name="action_reply">أجب</string>
<string name="action_reblog">عزز</string>
<string name="action_favourite">تفضيل</string>
<string name="action_more">المزيد</string>
<string name="action_compose">حرر</string>
<string name="action_login">التسجيل بواسطة ماستدون</string>
<string name="action_logout">خروج</string>
<string name="action_follow">إتبع</string>
<string name="action_unfollow">إلغاء التتبع</string>
<string name="action_block">حضر</string>
<string name="action_unblock">إلغاء الحظر</string>
<string name="action_report">أبلغ</string>
<string name="action_delete">إحذف</string>
<string name="action_send">تبويق</string>
<string name="action_send_public">بَوِّق</string>
<string name="action_retry">إعادة المحاولة</string>
<string name="action_hide_text">اخفي النص وراء تحذير</string>
<string name="action_ok">موافق</string>
<string name="action_cancel">إلغاء</string>
<string name="action_close">إغلاق</string>
<string name="action_back">عودة</string>
<string name="action_view_profile">الملف الشخصي</string>
<string name="action_view_preferences">التفضيلات</string>
<string name="action_view_favourites">المفضلة</string>
<string name="action_view_blocks">المستخدمون المحظورون</string>
<string name="action_view_thread">الخيط</string>
<string name="action_view_media">وسائط</string>
<string name="action_open_in_web">إفتح في متصفح</string>
<string name="action_submit">ارسل</string>
<string name="action_photo_pick">إضافة وسائط</string>
<string name="action_share">شارك</string>
<string name="action_mute">أكتم</string>
<string name="action_unmute">إلغاء الكتم</string>
<string name="action_mention">أذكر</string>
<string name="toggle_nsfw">NSFW</string>
<string name="action_compose_options">خيارات</string>
<string name="action_open_drawer">إفتح الدرج</string>
<string name="action_clear">إمسح</string>
<string name="send_status_to">شارك رابط التبويق إلى ...</string>
<string name="search">ابحث عن حسابات ...</string>
<string name="confirmation_send">بَوِّق</string>
<string name="confirmation_reported">تم الإرسال !</string>
<string name="hint_domain">أي سيرفر ؟</string>
<string name="hint_compose">ما الجديد ؟</string>
<string name="hint_content_warning">تحذير عن المحتوى</string>
<string name="link_whats_an_instance">ماذا نعني بمثيل الخادم ؟</string>
<string name="dialog_title_finishing_media_upload">تتمة رفع الوسائط</string>
<string name="dialog_message_uploading_media">جاري الرفع ...</string>
<string name="pref_title_notification_settings">الاشعارات</string>
<string name="pref_title_edit_notification_settings">تعديل الاشعارات</string>
<string name="pref_title_notifications_enabled">دفع الإخطارات</string>
<string name="pref_title_notification_alerts">التنبيهات</string>
<string name="pref_title_notification_alert_sound">إعلام بالصوت</string>
<string name="pref_title_notification_alert_vibrate">إعلام بالاهتزار</string>
<string name="pref_title_notification_alert_light">إعلام بالضوء</string>
<string name="pref_title_notification_filters">أخطرني عندما</string>
<string name="pref_title_notification_filter_mentions">يشار إلي</string>
<string name="pref_title_notification_filter_follows">يتبعني أحد</string>
<string name="pref_title_notification_filter_reblogs">تعزز وتدفع منشوراتي</string>
<string name="pref_title_notification_filter_favourites">يعجب أحد ما بمنشوراتي</string>
<string name="pref_title_appearance_settings">المظهر</string>
<string name="pref_title_light_theme">إستخدم سمةً فاتحة اللون</string>
<string name="pref_title_browser_settings">المتصفح</string>
<string name="pref_title_custom_tabs">إخفاء زر المتابعة أثناء تمرير الصفحة</string>
<string name="notification_mention_format">%s أشار إليك</string>
<string name="notification_summary_large">%1$s, %2$s, %3$s و %4$d أخرى</string>
<string name="notification_summary_medium">%1$s, %2$s, و %3$s</string>
<string name="notification_summary_small">%1$s و %2$s</string>
<string name="notification_title_summary">%d تفاعلات جديدة</string>
<string name="description_account_locked">حساب مقفل</string>
</resources>

View file

@ -10,16 +10,22 @@
<string name="error_media_upload_image_or_video">Bilder und Videos können beide nicht an den Beitrag angehängt werden.</string> <string name="error_media_upload_image_or_video">Bilder und Videos können beide nicht an den Beitrag angehängt werden.</string>
<string name="error_media_upload_sending">Die Mediendatei konnte nicht hochgeladen werden.</string> <string name="error_media_upload_sending">Die Mediendatei konnte nicht hochgeladen werden.</string>
<string name="error_report_too_few_statuses">Mindestens ein Beitrag muss berichtet werden.</string> <string name="error_report_too_few_statuses">Mindestens ein Beitrag muss berichtet werden.</string>
<string name="error_authorization_denied">Autorisierung fehlgeschlagen.</string>
<string name="error_generic">Ein Fehler ist aufgetreten.</string>
<string name="error_no_web_browser_found">Kein Webbrowser gefunden.</string>
<string name="error_retrieving_oauth_token">Es konnte kein Login-Token abgerufen werden.</string>
<string name="title_home">Start</string> <string name="title_home">Start</string>
<string name="title_notifications">Benachrichtigungen</string> <string name="title_notifications">Benachrichtigungen</string>
<string name="title_public_local">Lokal</string>
<string name="title_public_federated">Föderiert</string>
<string name="title_thread">Unterhaltung</string> <string name="title_thread">Unterhaltung</string>
<string name="title_tag">#%s</string> <string name="title_tag">#%s</string>
<string name="title_statuses">Beiträge</string> <string name="title_statuses">Beiträge</string>
<string name="title_follows">Folgt</string> <string name="title_follows">Folgt</string>
<string name="title_followers">Folgende</string> <string name="title_followers">Folgende</string>
<string name="title_favourites">Favoriten</string> <string name="title_favourites">Favoriten</string>
<string name="title_blocks">Blockierte Nutzer</string> <string name="title_blocks">Blockierte Accounts</string>
<string name="status_username_format">\@%s</string> <string name="status_username_format">\@%s</string>
<string name="status_boosted_format">%s teilte</string> <string name="status_boosted_format">%s teilte</string>
@ -68,6 +74,16 @@
<string name="action_mute">Stummschalten</string> <string name="action_mute">Stummschalten</string>
<string name="action_unmute">Lautschalten</string> <string name="action_unmute">Lautschalten</string>
<string name="action_mention">Erwähnen</string> <string name="action_mention">Erwähnen</string>
<string name="action_reply">Antworten</string>
<string name="action_reblog">Teilen</string>
<string name="action_favourite">Favorisieren</string>
<string name="action_more">Mehr</string>
<string name="action_view_thread">Thread</string>
<string name="action_view_media">Medien</string>
<string name="action_compose_options">Einstellungen</string>
<string name="action_open_drawer">Drawer öffnen</string>
<string name="action_clear">Löschen</string>
<string name="toggle_nsfw">NSFW</string> <string name="toggle_nsfw">NSFW</string>
<string name="send_status_to">Teile Toot-URL zu…</string> <string name="send_status_to">Teile Toot-URL zu…</string>
@ -104,22 +120,23 @@
<string name="pref_title_appearance_settings">Aussehen</string> <string name="pref_title_appearance_settings">Aussehen</string>
<string name="pref_title_light_theme">Benutze helles Theme</string> <string name="pref_title_light_theme">Benutze helles Theme</string>
<string name="pref_title_notification_alerts">Benachrichtigungen</string>
<string name="pref_title_edit_notification_settings">Benachrichtigungseinstellungen</string>
<string name="pref_title_notification_filter_favourites">Jemandem meine Posts gefallen</string>
<string name="pref_title_notification_filters">Benachrichtigen wenn</string>
<string name="pref_title_notification_filter_follows">Mir jemand folgt</string>
<string name="pref_title_notification_filter_mentions">Ich erwähnt werde</string>
<string name="pref_title_notification_filter_reblogs">Jemand meine Posts teilt</string>
<string name="pref_title_browser_settings">Browser</string>
<string name="pref_title_custom_tabs">Öffne Links in der App</string>
<string name="pref_title_hide_follow_button">Verstecke Button bei Bildlauf </string>
<string name="notification_mention_format">%s hat dich erwähnt</string> <string name="notification_mention_format">%s hat dich erwähnt</string>
<string name="notification_summary_large">%1$s, %2$s, %3$s und %4$d andere</string> <string name="notification_summary_large">%1$s, %2$s, %3$s und %4$d andere</string>
<string name="notification_summary_medium">%1$s, %2$s, und %3$s</string> <string name="notification_summary_medium">%1$s, %2$s, und %3$s</string>
<string name="notification_summary_small">%1$s und %2$s</string> <string name="notification_summary_small">%1$s und %2$s</string>
<string name="notification_title_summary">%d neue Interaktionen</string> <string name="notification_title_summary">%d neue Interaktionen</string>
<string name="title_public_local">Lokal</string>
<string name="title_public_federated">Föderiert</string>
<string name="pref_title_notification_alerts">Benachrichtigungen</string>
<string name="pref_title_notification_filter_favourites">Jemandem meine Posts gefallen</string>
<string name="pref_title_notification_filters">Benachrichtigen wenn</string>
<string name="pref_title_notification_filter_follows">Mir jemand folgt</string>
<string name="pref_title_notification_filter_mentions">Ich erwähnt werde</string>
<string name="pref_title_notification_filter_reblogs">Jemand meine Posts boostet</string>
<string name="error_authorization_denied">Autorisierung fehlgeschlagen.</string>
<string name="error_generic">Ein Fehler ist aufgetreten.</string>
<string name="error_no_web_browser_found">Kein Webbrowser gefunden.</string>
<string name="error_retrieving_oauth_token">Es konnte kein Login-Token abgerufen werden.</string>
</resources> <string name="description_account_locked">Gesperrter Account</string>
</resources>

View file

@ -1,30 +1,30 @@
<resources> <resources>
<string name="error_generic">Une erreur s\'est produite.</string> <string name="error_generic">Une erreur sest produite.</string>
<string name="error_invalid_domain">Le domaine est invalide</string> <string name="error_invalid_domain">Le domaine est invalide</string>
<string name="error_failed_app_registration">L\'application n\'a pu s\'authentifier avec l\'instance.</string> <string name="error_failed_app_registration">Lapplication na pu sauthentifier avec linstance.</string>
<string name="error_no_web_browser_found">Impossible de trouver un navigateur web.</string> <string name="error_no_web_browser_found">Impossible de trouver un navigateur web.</string>
<string name="error_authorization_unknown">Une erreur d\'authorisation inconnu s\'est produite.</string> <string name="error_authorization_unknown">Une erreur dautorisation inconnue sest produite.</string>
<string name="error_authorization_denied">Vous ne pouvez pas vous authentifier.</string> <string name="error_authorization_denied">Vous ne pouvez pas vous authentifier.</string>
<string name="error_retrieving_oauth_token">Impossible de récupérer le jeton d\'authentification.</string> <string name="error_retrieving_oauth_token">Impossible de récupérer le jeton dauthentification.</string>
<string name="error_compose_character_limit">Votre pouet est trop long!</string> <string name="error_compose_character_limit">Votre pouet est trop long!</string>
<string name="error_media_upload_size">Le fichier doit faire moins de 4Mo.</string> <string name="error_media_upload_size">Le fichier doit faire moins de 4Mo.</string>
<string name="error_media_upload_type">Ce type de fichier n\'est pas accepté.</string> <string name="error_media_upload_type">Ce type de fichier nest pas accepté.</string>
<string name="error_media_upload_opening">Le fichier ne peut être ouvert.</string> <string name="error_media_upload_opening">Le fichier ne peut être ouvert.</string>
<string name="error_media_upload_permission">Une permision pour lire ce média est requis pour l\'uploader.</string> <string name="error_media_upload_permission">Une permission pour lire ce média est requis pour le mettre en ligne.</string>
<string name="error_media_upload_image_or_video">Impossible de mettre une vidéo et une image sur le même pouet.</string> <string name="error_media_upload_image_or_video">Impossible de mettre une vidéo et une image sur le même pouet.</string>
<string name="error_media_upload_sending">Ce média ne peut être uploadé.</string> <string name="error_media_upload_sending">Ce média ne peut être mis en ligne.</string>
<string name="error_report_too_few_statuses">Au moins un pouet a été reporté.</string> <string name="error_report_too_few_statuses">Au moins un pouet a été reporté.</string>
<string name="title_home">Accueil</string> <string name="title_home">Accueil</string>
<string name="title_notifications">Notifications</string> <string name="title_notifications">Notifications</string>
<string name="title_public_local">Local</string> <string name="title_public_local">Local</string>
<string name="title_public_federated">Fédéré</string> <string name="title_public_federated">Fédéré</string>
<string name="title_thread">Thread</string> <string name="title_thread">Fil</string>
<string name="title_tag">#%s</string> <string name="title_tag">#%s</string>
<string name="title_statuses">Pouets</string> <string name="title_statuses">Pouets</string>
<string name="title_follows">Follows</string> <string name="title_follows">Abonnements</string>
<string name="title_followers">Followers</string> <string name="title_followers">Abonnés</string>
<string name="title_favourites">Favoris</string> <string name="title_favourites">Favoris</string>
<string name="title_blocks">Utilisateur bloqués</string> <string name="title_blocks">Utilisateur bloqués</string>
@ -40,24 +40,25 @@
<string name="footer_end_of_accounts">fin des comptes</string> <string name="footer_end_of_accounts">fin des comptes</string>
<string name="notification_reblog_format">%s à boosté votre pouet</string> <string name="notification_reblog_format">%s à boosté votre pouet</string>
<string name="notification_favourite_format">%s à ajouter votre pouet en favoris</string> <string name="notification_favourite_format">%s a ajouté votre pouet dans ses favoris</string>
<string name="notification_follow_format">%s vous suit</string> <string name="notification_follow_format">%s vous suit</string>
<string name="report_username_format">Signaler @%s</string> <string name="report_username_format">Signaler @%s</string>
<string name="report_comment_hint">Plus de commentaire ?</string> <string name="report_comment_hint">Davantage de commentaires ?</string>
<string name="action_compose">Écrire</string> <string name="action_compose">Répondre</string>
<string name="action_login">Se connecter avec Mastodon</string> <string name="action_login">Se connecter avec Mastodon</string>
<string name="action_logout">Deconnexion</string> <string name="action_logout">Deconnexion</string>
<string name="action_follow">Follow</string>
<string name="action_unfollow">Unfollow</string> <string name="action_follow">Suivre</string>
<string name="action_unfollow">Ne plus suivre</string>
<string name="action_block">Bloquer</string> <string name="action_block">Bloquer</string>
<string name="action_unblock">Débloquer</string> <string name="action_unblock">Débloquer</string>
<string name="action_report">Signaler</string> <string name="action_report">Signaler</string>
<string name="action_delete">Supprimer</string> <string name="action_delete">Supprimer</string>
<string name="action_send">POUET</string> <string name="action_send">POUET</string>
<string name="action_send_public">POUET!</string> <string name="action_send_public">POUET !</string>
<string name="action_retry">Ré-essayer</string> <string name="action_retry">Essayer encore</string>
<string name="action_mark_sensitive">Définir le média comme sensible</string> <string name="action_mark_sensitive">Définir le média comme sensible</string>
<string name="action_hide_text">Masquer le texte par une mise en garde</string> <string name="action_hide_text">Masquer le texte par une mise en garde</string>
<string name="action_ok">Ok</string> <string name="action_ok">Ok</string>
@ -76,52 +77,65 @@
<string name="action_unmute">Redonner la parole</string> <string name="action_unmute">Redonner la parole</string>
<string name="action_mention">Mention</string> <string name="action_mention">Mention</string>
<string name="toggle_nsfw">NSFW</string> <string name="toggle_nsfw">NSFW</string>
<string name="action_open_drawer">Ouvrir le menu</string>
<string name="action_more">Plus</string>
<string name="action_reply">Répondre</string>
<string name="action_view_media">Media</string>
<string name="action_favourite">Favori</string>
<string name="action_compose_options">Option</string>
<string name="action_clear">Nettoyer</string>
<string name="action_reblog">Boost</string>
<string name="send_status_to">Partager l\'URL de votre pouet avec…</string> <string name="send_status_to">Partager lURL de votre pouet avec…</string>
<string name="search">Rechercher un compte…</string> <string name="search">Rechercher un compte…</string>
<string name="confirmation_send">Toot!</string> <string name="confirmation_send">Toot!</string>
<string name="confirmation_reported">Envoyer!</string> <string name="confirmation_reported">Envoyer !</string>
<string name="hint_domain">Quelle instance?</string> <string name="hint_domain">Quelle instance ?</string>
<string name="hint_compose">Quoi de neuf ?</string> <string name="hint_compose">Quoi de neuf ?</string>
<string name="hint_content_warning">Contenu mis en garde</string> <string name="hint_content_warning">Contenu sensible</string>
<string name="link_whats_an_instance">Qu\'est ce qu\'une instance?</string> <string name="link_whats_an_instance">Quest ce quune instance ?</string>
<string name="dialog_whats_an_instance">L\'adresse ou le domaine d\'une instance peut être entré <string name="dialog_whats_an_instance">Ladresse ou le domaine dune instance peut être entré
Ici, comme mastodon.social, icosahedron.website, social.tchncs.de, et Ici, comme mastodon.social, icosahedron.website, social.tchncs.de, et
<a href="https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md">plus (en anglais)!</a> <a href="https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md">plus (en anglais)!</a>
\n\nSi vous n\'avez pas de compte, Vous pouvez entrer le nom de l\'instance que vous voulez rejoindre et créer un compte ici.\n\n Une instance est l\'endroit où votre compte est \n\nSi vous navez pas de compte, Vous pouvez entrer le nom de linstance que vous voulez rejoindre et créer un compte ici.\n\n Une instance est lendroit où votre compte est
stocké, mais vous pouvez facilement communiquer et suivre d\'autre personne sur d\'autre instance bien que vous soyez sur le même site stocké, mais vous pouvez facilement communiquer et suivre dautre personne sur dautres instances bien que vous soyez sur le même site
\n\nPlus d\'info <a href="https://mastodon.social/about">mastodon.social</a> (anglais). \n\nPlus dinfo <a href="https://mastodon.social/about">mastodon.social</a> (anglais).
</string> </string>
<string name="dialog_title_finishing_media_upload">Média uploadé avec succès</string> <string name="dialog_title_finishing_media_upload">Média mis en ligne avec succès</string>
<string name="dialog_message_uploading_media">Téléversement</string> <string name="dialog_message_uploading_media">Mise en ligne</string>
<string name="visibility_public">Tout le monde peut voir</string> <string name="visibility_public">Afficher dans les fils publics</string>
<string name="visibility_unlisted">Tout le monde peut voir, mais cela ne sera pas listé sur votre timeline public</string> <string name="visibility_unlisted">Ne pas afficher dans les fils publics</string>
<string name="visibility_private">Uniquement les followers et les mentionnés peuvent voir</string> <string name="visibility_private">Nafficher que pour vos abonné⋅e⋅s</string>
<string name="pref_title_notification_settings">Notifications</string> <string name="pref_title_notification_settings">Notifications</string>
<string name="pref_title_edit_notification_settings">Modifier la notification</string>
<string name="pref_title_notifications_enabled">Notifications push</string> <string name="pref_title_notifications_enabled">Notifications push</string>
<string name="pref_title_notification_alerts">Alertes</string> <string name="pref_title_notification_alerts">Alertes</string>
<string name="pref_title_notification_alert_sound">Sonner pour notifier</string> <string name="pref_title_notification_alert_sound">Émettre un son pour notifier</string>
<string name="pref_title_notification_alert_vibrate">Vibrer pour notifier</string> <string name="pref_title_notification_alert_vibrate">Vibrer pour notifier</string>
<string name="pref_title_notification_alert_light">Notifier avec une LED</string> <string name="pref_title_notification_alert_light">Notifier avec une LED</string>
<string name="pref_title_notification_filters">Me notifier quand</string> <string name="pref_title_notification_filters">Me notifier quand</string>
<string name="pref_title_notification_filter_mentions">mentionné</string> <string name="pref_title_notification_filter_mentions">mentionné</string>
<string name="pref_title_notification_filter_follows">suivit</string> <string name="pref_title_notification_filter_follows">suivi</string>
<string name="pref_title_notification_filter_reblogs">mes pouets boostés</string> <string name="pref_title_notification_filter_reblogs">mes pouets boostés</string>
<string name="pref_title_notification_filter_favourites">mes pouets mis en favoris</string> <string name="pref_title_notification_filter_favourites">mes pouets mis en favoris</string>
<string name="pref_title_appearance_settings">Apparence</string> <string name="pref_title_appearance_settings">Apparence</string>
<string name="pref_title_light_theme">Utiliser le thème clair</string> <string name="pref_title_light_theme">Utiliser le thème clair</string>
<string name="pref_title_browser_settings">Navigateur</string>
<string name="pref_title_custom_tabs">Utiliser le navigateur intégré</string>
<string name="pref_title_hide_follow_button">Cacher le bouton de suivi lors du défilement</string>
<string name="notification_mention_format">%s vous ont mentionnés</string> <string name="notification_mention_format">%s vous ont mentionné⋅e</string>
<string name="notification_summary_large">%1$s, %2$s, %3$s et %4$d plus</string> <string name="notification_summary_large">%1$s, %2$s, %3$s et %4$d plus</string>
<string name="notification_summary_medium">%1$s, %2$s, et %3$s</string> <string name="notification_summary_medium">%1$s, %2$s, et %3$s</string>
<string name="notification_summary_small">%1$s et %2$s</string> <string name="notification_summary_small">%1$s et %2$s</string>
<string name="notification_title_summary">%d nouvelles interactions</string> <string name="notification_title_summary">%d nouvelles interactions</string>
</resources> <string name="description_account_locked">Compte bloqué</string>
</resources>

View file

@ -0,0 +1,142 @@
<resources>
<string name="error_generic">エラーが発生しました。</string>
<string name="error_invalid_domain">不正なドメイン名が入力されました</string>
<string name="error_failed_app_registration">そのインスタンスでの認証が失敗しました</string>
<string name="error_no_web_browser_found">使用するブラウザを見つけることができません。</string>
<string name="error_authorization_unknown">未定義の認証エラーが発生しました。</string>
<string name="error_authorization_denied">認証は拒否されました。</string>
<string name="error_retrieving_oauth_token">ログイントークンの取得に失敗しました。</string>
<string name="error_compose_character_limit">ステータスが非常に長い!</string>
<string name="error_media_upload_size">ファイルは4MB未満にしてください。</string>
<string name="error_media_upload_type">このファイル種別はアップロードできません。</string>
<string name="error_media_upload_opening">このファイルは開けません。</string>
<string name="error_media_upload_permission">メディアの読み込み権限が必要です。</string>
<string name="error_media_upload_image_or_video">同一のステータスに画像とビデオを一緒にすることはできません。</string>
<string name="error_media_upload_sending">アップロードに失敗しました。</string>
<string name="error_report_too_few_statuses">少なくとも1つのステータスを報告してください。</string>
<string name="title_home">ホーム</string>
<string name="title_notifications">通知</string>
<string name="title_public_local">ローカル</string>
<string name="title_public_federated">連合</string>
<string name="title_thread">スレッド</string>
<string name="title_tag">#%s</string>
<string name="title_statuses">投稿</string>
<string name="title_follows">フォロー</string>
<string name="title_followers">フォロワー</string>
<string name="title_favourites">お気に入り</string>
<string name="title_blocks">ブロックしたユーザー</string>
<string name="status_username_format">\@%s</string>
<string name="status_boosted_format">%s 加速されました</string>
<string name="status_sensitive_media_title">不適切なメディア</string>
<string name="status_sensitive_media_directions">タップして表示</string>
<string name="status_content_warning_show_more">さらに表示</string>
<string name="status_content_warning_show_less">省略表示</string>
<string name="footer_end_of_statuses">これ以降にステータスはありません</string>
<string name="footer_end_of_notifications">これ以降に通知はありません</string>
<string name="footer_end_of_accounts">これ以降にアカウントはありません</string>
<string name="notification_reblog_format">%s があたなのトゥートをブーストしました</string>
<string name="notification_favourite_format">%s があなたのトゥートをお気に入りに追加しました</string>
<string name="notification_follow_format">%s があなたをフォローしました</string>
<string name="report_username_format">\@%s を通報</string>
<string name="report_comment_hint">コメントを追加しますか?</string>
<string name="action_reply">返信</string>
<string name="action_reblog">ブースト</string>
<string name="action_favourite">お気に入り</string>
<string name="action_more">もっと読む</string>
<string name="action_compose">作成</string>
<string name="action_login">Mastodonにログイン</string>
<string name="action_logout">ログアウト</string>
<string name="action_follow">フォロー</string>
<string name="action_unfollow">フォロー解除</string>
<string name="action_block">ブロック</string>
<string name="action_unblock">ブロック解除</string>
<string name="action_report">報告</string>
<string name="action_delete">削除</string>
<string name="action_send">トゥート</string>
<string name="action_send_public">トゥート!</string>
<string name="action_retry">リトライ</string>
<string name="action_mark_sensitive">不適切なメディアとする</string>
<string name="action_hide_text">警告のあるテキストを隠す</string>
<string name="action_ok">Ok</string>
<string name="action_cancel">キャンセル</string>
<string name="action_close">閉じる</string>
<string name="action_back">戻る</string>
<string name="action_view_profile">プロファイル</string>
<string name="action_view_preferences">設定</string>
<string name="action_view_favourites">お気に入り</string>
<string name="action_view_blocks">ブロックしたユーザー</string>
<string name="action_view_thread">スレッド</string>
<string name="action_view_media">メディア</string>
<string name="action_open_in_web">ブラウザで開く</string>
<string name="action_submit">投稿</string>
<string name="action_photo_pick">メディアを追加</string>
<string name="action_share">共有</string>
<string name="action_mute">ミュート</string>
<string name="action_unmute">ミュート解除</string>
<string name="action_mention">メンション</string>
<string name="toggle_nsfw">NSFW</string>
<string name="action_compose_options">オプション</string>
<string name="action_open_drawer">ドローワを開く</string>
<string name="action_clear">クリア</string>
<string name="send_status_to">トゥートURLを共通…</string>
<string name="search">アカウントを検索…</string>
<string name="confirmation_send">トゥート!</string>
<string name="confirmation_reported">送信しました!</string>
<string name="hint_domain">どのインスタンス?</string>
<string name="hint_compose">今何してる?</string>
<string name="hint_content_warning">コンテンツの警告</string>
<string name="link_whats_an_instance">インスタンスって?</string>
<string name="dialog_whats_an_instance">インスタンスのアドレスもしくはドメインをここに入力してください。
例えば mastodon.social, mstdn.jp, pawoo.net, や
<a href="https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md">などです!</a>
\n\nもしアカウントを持っていない場合は、参加したいインスタンスの名前を入力してください。\n\n
インスタンスはあなたのアカウントを単一の場所で管理(ホスト)しますが、ほかのインスタンスと同じサイトであるかのように人をフォローしたり連絡することができます。
\n\n詳しくは<a href="https://mastodon.social/about">mastodon.social</a>を見てください。
</string>
<string name="dialog_title_finishing_media_upload">メディアのアップロードが完了</string>
<string name="dialog_message_uploading_media">アップロード中…</string>
<string name="visibility_public">すべての人が表示可能</string>
<string name="visibility_unlisted">すべての人が表示可能だが公開タイムラインには載せない</string>
<string name="visibility_private">フォロワーとメンションのみ表示可能</string>
<string name="pref_title_notification_settings">通知</string>
<string name="pref_title_edit_notification_settings">通知を編集</string>
<string name="pref_title_notifications_enabled">プッシュ通知</string>
<string name="pref_title_notification_alerts">アラート</string>
<string name="pref_title_notification_alert_sound">音で通知</string>
<string name="pref_title_notification_alert_vibrate">バイブレーションで通知</string>
<string name="pref_title_notification_alert_light">ライトで通知</string>
<string name="pref_title_notification_filters">通知する状態</string>
<string name="pref_title_notification_filter_mentions">メンションがありました</string>
<string name="pref_title_notification_filter_follows">フォローされた</string>
<string name="pref_title_notification_filter_reblogs">私の投稿がブーストされました</string>
<string name="pref_title_notification_filter_favourites">私の投稿がお気に入りに追加されました</string>
<string name="pref_title_appearance_settings">表示</string>
<string name="pref_title_light_theme">明るいテーマを使用</string>
<string name="pref_title_browser_settings">ブラウザ</string>
<string name="pref_title_custom_tabs">Chromeカスタムタブを使用</string>
<string name="pref_title_hide_follow_button">スクロール中にフォローボタンを非表示</string>
<string name="notification_mention_format">%s があなたにメンションを送信しました</string>
<string name="notification_summary_large">%1$s、%2$s、%3$s と他に%4$d件</string>
<string name="notification_summary_medium">%1$s、%2$s、と %3$s</string>
<string name="notification_summary_small">%1$s と %2$s</string>
<string name="notification_title_summary">%d 新しいお知らせ</string>
<string name="description_account_locked">ロックされたアカウント</string>
</resources>

View file

@ -1,6 +1,7 @@
<resources> <resources>
<string name="error_generic">An error occurred.</string> <string name="error_generic">An error occurred.</string>
<string name="error_empty">This cannot be empty.</string>
<string name="error_invalid_domain">Invalid domain entered</string> <string name="error_invalid_domain">Invalid domain entered</string>
<string name="error_failed_app_registration">Failed authenticating with that instance.</string> <string name="error_failed_app_registration">Failed authenticating with that instance.</string>
<string name="error_no_web_browser_found">Couldn\'t find a web browser to use.</string> <string name="error_no_web_browser_found">Couldn\'t find a web browser to use.</string>
@ -39,6 +40,7 @@
<string name="footer_end_of_statuses">end of the statuses</string> <string name="footer_end_of_statuses">end of the statuses</string>
<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="footer_empty">There are no toots here so far. Pull down to refresh!</string>
<string name="notification_reblog_format">%s boosted your toot</string> <string name="notification_reblog_format">%s boosted your toot</string>
<string name="notification_favourite_format">%s favourited your toot</string> <string name="notification_favourite_format">%s favourited your toot</string>
@ -89,7 +91,8 @@
<string name="action_save">Save</string> <string name="action_save">Save</string>
<string name="action_edit_profile">Edit profile</string> <string name="action_edit_profile">Edit profile</string>
<string name="send_status_to">Share toot URL to…</string> <string name="send_status_link_to">Share toot URL to…</string>
<string name="send_status_content_to">Share toot to…</string>
<string name="search">Search accounts…</string> <string name="search">Search accounts…</string>
@ -148,5 +151,7 @@
<string name="notification_title_summary">%d new interactions</string> <string name="notification_title_summary">%d new interactions</string>
<string name="description_account_locked">Locked Account</string> <string name="description_account_locked">Locked Account</string>
<string name="status_share_content">Share content of toot</string>
<string name="status_share_link">Share link to toot</string>
</resources> </resources>