diff --git a/.github/workflows/label-bugs.yml b/.github/workflows/label-bugs.yml
index 6bbb86e8..0b1e2963 100644
--- a/.github/workflows/label-bugs.yml
+++ b/.github/workflows/label-bugs.yml
@@ -16,3 +16,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: 'bug'
+ - name: Remove runs
+ uses: GongT/cancel-previous-workflows@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ DELETE: 'yes'
diff --git a/.github/workflows/label-duplicates.yml b/.github/workflows/label-duplicates.yml
index bffe2a54..4cfd39f5 100644
--- a/.github/workflows/label-duplicates.yml
+++ b/.github/workflows/label-duplicates.yml
@@ -16,3 +16,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: 'duplicate'
+ - name: Remove runs
+ uses: GongT/cancel-previous-workflows@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ DELETE: 'yes'
diff --git a/app/src/github/res/values-mk/strings.xml b/app/src/github/res/values-mk/strings.xml
index 078fa6a8..1ef096e9 100644
--- a/app/src/github/res/values-mk/strings.xml
+++ b/app/src/github/res/values-mk/strings.xml
@@ -1,6 +1,6 @@
- Enable Sentry
- Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io
- Sentry will start on next launch
+ Овозможи Sentry
+ Sentry е слушач на грешки кој асинхроно ги испраќа на Sentry.io страната
+ Sentry ќе биде овозможен на следно отварање
diff --git a/app/src/github/res/values-or/strings.xml b/app/src/github/res/values-or/strings.xml
index 078fa6a8..173bf73c 100644
--- a/app/src/github/res/values-or/strings.xml
+++ b/app/src/github/res/values-or/strings.xml
@@ -1,6 +1,6 @@
- Enable Sentry
- Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io
- Sentry will start on next launch
+ Sentryକୁ ସକ୍ଷମ କରନ୍ତୁ
+ ତ୍ରୁଟି ପାଇଁ ସେଣ୍ଟ୍ରି ହେଉଛି ଏକ ଶ୍ରୋତା ଯାହା ତ୍ରୁଟି / ଘଟଣାକୁ Sentry.io କୁ ପଠାଏ |
+ ପରବର୍ତ୍ତୀ ଲଞ୍ଚଠାରୁ ସେଣ୍ଟ୍ରି ଆରମ୍ଭ ହେବ |
diff --git a/app/src/main/java/awais/instagrabber/adapters/StoriesAdapter.java b/app/src/main/java/awais/instagrabber/adapters/StoriesAdapter.java
index 9a502f01..21a5b621 100755
--- a/app/src/main/java/awais/instagrabber/adapters/StoriesAdapter.java
+++ b/app/src/main/java/awais/instagrabber/adapters/StoriesAdapter.java
@@ -1,5 +1,7 @@
package awais.instagrabber.adapters;
+import java.util.List;
+
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -72,6 +74,16 @@ public final class StoriesAdapter extends ListAdapter list = getCurrentList();
+ for (int i = 0; i < list.size(); i++) {
+ final StoryMedia item = list.get(i);
+ if (!item.isCurrentSlide() && i != newIndex) continue;
+ item.setCurrentSlide(i == newIndex);
+ notifyItemChanged(i, item);
+ }
+ }
+
public interface OnItemClickListener {
void onItemClick(StoryMedia storyModel, int position);
}
diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java
deleted file mode 100644
index 2a046d66..00000000
--- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java
+++ /dev/null
@@ -1,1316 +0,0 @@
-package awais.instagrabber.fragments;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.drawable.Animatable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.view.GestureDetectorCompat;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.navigation.NavController;
-import androidx.navigation.NavDirections;
-import androidx.navigation.fragment.NavHostFragment;
-import androidx.recyclerview.widget.LinearLayoutManager;
-
-import com.facebook.drawee.backends.pipeline.Fresco;
-import com.facebook.drawee.controller.BaseControllerListener;
-import com.facebook.drawee.interfaces.DraweeController;
-import com.facebook.imagepipeline.image.ImageInfo;
-import com.facebook.imagepipeline.request.ImageRequest;
-import com.facebook.imagepipeline.request.ImageRequestBuilder;
-import com.google.android.exoplayer2.MediaItem;
-import com.google.android.exoplayer2.Player;
-import com.google.android.exoplayer2.SimpleExoPlayer;
-import com.google.android.exoplayer2.source.LoadEventInfo;
-import com.google.android.exoplayer2.source.MediaLoadData;
-import com.google.android.exoplayer2.source.MediaSource;
-import com.google.android.exoplayer2.source.MediaSourceEventListener;
-import com.google.android.exoplayer2.source.ProgressiveMediaSource;
-import com.google.android.exoplayer2.source.dash.DashMediaSource;
-import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
-
-import java.io.IOException;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import awais.instagrabber.BuildConfig;
-import awais.instagrabber.R;
-import awais.instagrabber.adapters.StoriesAdapter;
-import awais.instagrabber.customviews.helpers.SwipeGestureListener;
-import awais.instagrabber.databinding.FragmentStoryViewerBinding;
-import awais.instagrabber.fragments.main.ProfileFragmentDirections;
-import awais.instagrabber.fragments.settings.PreferenceKeys;
-import awais.instagrabber.interfaces.SwipeEvent;
-import awais.instagrabber.models.enums.MediaItemType;
-import awais.instagrabber.repositories.requests.StoryViewerOptions;
-import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
-import awais.instagrabber.repositories.requests.directmessages.ThreadIdsOrUserIds;
-import awais.instagrabber.repositories.responses.stories.Broadcast;
-import awais.instagrabber.repositories.responses.stories.PollSticker;
-import awais.instagrabber.repositories.responses.stories.QuestionSticker;
-import awais.instagrabber.repositories.responses.stories.QuizSticker;
-import awais.instagrabber.repositories.responses.stories.SliderSticker;
-import awais.instagrabber.repositories.responses.stories.Story;
-import awais.instagrabber.repositories.responses.stories.StoryAppAttribution;
-import awais.instagrabber.repositories.responses.stories.StoryCta;
-import awais.instagrabber.repositories.responses.stories.StoryMedia;
-import awais.instagrabber.repositories.responses.stories.Tally;
-import awais.instagrabber.utils.AppExecutors;
-import awais.instagrabber.utils.Constants;
-import awais.instagrabber.utils.CookieUtils;
-import awais.instagrabber.utils.CoroutineUtilsKt;
-import awais.instagrabber.utils.DownloadUtils;
-import awais.instagrabber.utils.ResponseBodyUtils;
-import awais.instagrabber.utils.TextUtils;
-import awais.instagrabber.utils.Utils;
-import awais.instagrabber.viewmodels.ArchivesViewModel;
-import awais.instagrabber.viewmodels.FeedStoriesViewModel;
-import awais.instagrabber.viewmodels.HighlightsViewModel;
-import awais.instagrabber.viewmodels.StoriesViewModel;
-import awais.instagrabber.webservices.DirectMessagesRepository;
-import awais.instagrabber.webservices.MediaRepository;
-import awais.instagrabber.webservices.ServiceCallback;
-import awais.instagrabber.webservices.StoriesRepository;
-import kotlinx.coroutines.Dispatchers;
-
-import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_THRESHOLD;
-import static awais.instagrabber.customviews.helpers.SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD;
-import static awais.instagrabber.fragments.settings.PreferenceKeys.MARK_AS_SEEN;
-import static awais.instagrabber.utils.Utils.settingsHelper;
-
-public class StoryViewerFragment extends Fragment {
- private static final String TAG = "StoryViewerFragment";
-
- private final String cookie = settingsHelper.getString(Constants.COOKIE);
-
- private AppCompatActivity fragmentActivity;
- private View root;
- private FragmentStoryViewerBinding binding;
- private String currentStoryUsername;
- private String highlightTitle;
- private StoriesAdapter storiesAdapter;
- private SwipeEvent swipeEvent;
- private GestureDetectorCompat gestureDetector;
- private StoriesRepository storiesRepository;
- private MediaRepository mediaRepository;
- private StoryMedia currentStory;
- private Broadcast live;
- private int slidePos;
- private int lastSlidePos;
- private String url;
- private PollSticker poll;
- private QuestionSticker question;
- private List mentions = new ArrayList();
- private QuizSticker quiz;
- private SliderSticker slider;
- private MenuItem menuDownload, menuDm, menuProfile;
- private SimpleExoPlayer player;
- // private boolean isHashtag;
- // private boolean isLoc;
- // private String highlight;
- private String actionBarTitle, actionBarSubtitle;
- private boolean fetching = false, sticking = false, shouldRefresh = true;
- private boolean downloadVisible = false, dmVisible = false, profileVisible = true;
- private int currentFeedStoryIndex;
- private double sliderValue;
- private StoriesViewModel storiesViewModel;
- private ViewModel viewModel;
- // private boolean isHighlight;
- // private boolean isArchive;
- // private boolean isNotification;
- private DirectMessagesRepository directMessagesRepository;
- private StoryViewerOptions options;
- private String csrfToken;
- private String deviceId;
- private long userId;
-
- @Override
- public void onCreate(@Nullable final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
- if (csrfToken == null) return;
- userId = CookieUtils.getUserIdFromCookie(cookie);
- deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
- fragmentActivity = (AppCompatActivity) requireActivity();
- storiesRepository = StoriesRepository.Companion.getInstance();
- mediaRepository = MediaRepository.Companion.getInstance();
- directMessagesRepository = DirectMessagesRepository.Companion.getInstance();
- setHasOptionsMenu(true);
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
- if (root != null) {
- shouldRefresh = false;
- return root;
- }
- binding = FragmentStoryViewerBinding.inflate(inflater, container, false);
- root = binding.getRoot();
- return root;
- }
-
- @Override
- public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
- if (!shouldRefresh) return;
- init();
- shouldRefresh = false;
- }
-
- @Override
- public void onCreateOptionsMenu(@NonNull final Menu menu, final MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.story_menu, menu);
- menuDownload = menu.findItem(R.id.action_download);
- menuDm = menu.findItem(R.id.action_dms);
- menuProfile = menu.findItem(R.id.action_profile);
- menuDownload.setVisible(downloadVisible);
- menuDm.setVisible(dmVisible);
- menuProfile.setVisible(profileVisible);
- }
-
- @Override
- public void onPrepareOptionsMenu(@NonNull final Menu menu) {
- // hide menu items from activity
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
- final Context context = getContext();
- if (context == null) return false;
- int itemId = item.getItemId();
- if (itemId == R.id.action_download) {
- downloadStory();
- return true;
- }
- if (itemId == R.id.action_dms) {
- final EditText input = new EditText(context);
- input.setHint(R.string.reply_hint);
- final AlertDialog ad = new AlertDialog.Builder(context)
- .setTitle(R.string.reply_story)
- .setView(input)
- .setPositiveButton(R.string.confirm, (d, w) -> directMessagesRepository.broadcastStoryReply(
- csrfToken,
- userId,
- deviceId,
- ThreadIdsOrUserIds.Companion.ofOneUser(String.valueOf(currentStory.getUser().getPk())),
- input.getText().toString(),
- currentStory.getId(),
- String.valueOf(currentStory.getUser().getPk()),
- CoroutineUtilsKt.getContinuation(
- (directThreadBroadcastResponse, throwable1) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable1 != null) {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "onFailure: ", throwable1);
- return;
- }
- Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
- }), Dispatchers.getIO()
- )
- ))
- .setNegativeButton(R.string.cancel, null)
- .show();
- ad.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
- input.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {}
-
- @Override
- public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
- ad.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!TextUtils.isEmpty(s));
- }
-
- @Override
- public void afterTextChanged(final Editable s) {}
- });
- return true;
- }
- if (itemId == R.id.action_profile) {
- openProfile("@" + currentStory.getUser().getPk());
- }
- return false;
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (player != null) {
- player.pause();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- if (actionBar != null) {
- actionBar.setTitle(actionBarTitle);
- actionBar.setSubtitle(actionBarSubtitle);
- }
- setHasOptionsMenu(true);
- }
-
- @Override
- public void onDestroy() {
- releasePlayer();
- // reset subtitle
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- if (actionBar != null) {
- actionBar.setSubtitle(null);
- }
- super.onDestroy();
- }
-
- private void init() {
- if (getArguments() == null) return;
- final StoryViewerFragmentArgs fragmentArgs = StoryViewerFragmentArgs.fromBundle(getArguments());
- options = fragmentArgs.getOptions();
- currentFeedStoryIndex = options.getCurrentFeedStoryIndex();
- // highlight = fragmentArgs.getHighlight();
- // isHighlight = !TextUtils.isEmpty(highlight);
- // isArchive = fragmentArgs.getIsArchive();
- // isNotification = fragmentArgs.getIsNotification();
- final Type type = options.getType();
- if (currentFeedStoryIndex >= 0) {
- switch (type) {
- case HIGHLIGHT:
- viewModel = new ViewModelProvider(fragmentActivity).get(HighlightsViewModel.class);
- break;
- case STORY_ARCHIVE:
- viewModel = new ViewModelProvider(fragmentActivity).get(ArchivesViewModel.class);
- break;
- default:
- case FEED_STORY_POSITION:
- viewModel = new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class);
- break;
- }
- }
- setupStories();
- }
-
- private void setupStories() {
- storiesViewModel = new ViewModelProvider(this).get(StoriesViewModel.class);
- setupListeners();
- final Context context = getContext();
- if (context == null) return;
- binding.storiesList.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
- storiesAdapter = new StoriesAdapter((model, position) -> {
- currentStory = model;
- slidePos = position;
- refreshStory();
- });
- binding.storiesList.setAdapter(storiesAdapter);
- storiesViewModel.getList().observe(fragmentActivity, storiesAdapter::submitList);
- resetView();
- }
-
- @SuppressLint("ClickableViewAccessibility")
- private void setupListeners() {
- final boolean hasFeedStories;
- List> models = null;
- if (currentFeedStoryIndex >= 0) {
- final Type type = options.getType();
- switch (type) {
- case HIGHLIGHT:
- final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel;
- models = highlightsViewModel.getList().getValue();
- break;
- case FEED_STORY_POSITION:
- final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel;
- models = feedStoriesViewModel.getList().getValue();
- break;
- case STORY_ARCHIVE:
- final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel;
- models = archivesViewModel.getList().getValue();
- break;
- }
- }
- hasFeedStories = models != null && !models.isEmpty();
- final List> finalModels = models;
- final Context context = getContext();
- if (context == null) return;
- swipeEvent = isRightSwipe -> {
- final List storyModels = storiesViewModel.getList().getValue();
- final int storiesLen = storyModels == null ? 0 : storyModels.size();
- if (sticking) {
- Toast.makeText(context, R.string.follower_wait_to_load, Toast.LENGTH_SHORT).show();
- return;
- }
- if (storiesLen <= 0) return;
- final boolean isLeftSwipe = !isRightSwipe;
- final boolean endOfCurrentStories = slidePos + 1 >= storiesLen;
- final boolean swipingBeyondCurrentStories = (endOfCurrentStories && isLeftSwipe) || (slidePos == 0 && isRightSwipe);
- if (swipingBeyondCurrentStories && hasFeedStories) {
- final int index = currentFeedStoryIndex;
- if ((isRightSwipe && index == 0) || (isLeftSwipe && index == finalModels.size() - 1)) {
- Toast.makeText(context, R.string.no_more_stories, Toast.LENGTH_SHORT).show();
- return;
- }
- removeStickers();
- final Object feedStoryModel = isRightSwipe
- ? finalModels.get(index - 1)
- : finalModels.size() == index + 1 ? null : finalModels.get(index + 1);
- paginateStories(feedStoryModel, finalModels.get(index), context, isRightSwipe, currentFeedStoryIndex == finalModels.size() - 2);
- return;
- }
- removeStickers();
- if (isRightSwipe) {
- if (--slidePos <= 0) {
- slidePos = 0;
- }
- } else if (++slidePos >= storiesLen) {
- slidePos = storiesLen - 1;
- }
- currentStory = storyModels.get(slidePos);
- refreshStory();
- };
- gestureDetector = new GestureDetectorCompat(context, new SwipeGestureListener(swipeEvent));
- binding.playerView.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event));
- final GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) {
- final float diffX = e2.getX() - e1.getX();
- try {
- if (Math.abs(diffX) > Math.abs(e2.getY() - e1.getY()) && Math.abs(diffX) > SWIPE_THRESHOLD
- && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
- swipeEvent.onSwipe(diffX > 0);
- return true;
- }
- } catch (final Exception e) {
- // if (logCollector != null)
- // logCollector.appendException(e, LogCollector.LogFile.ACTIVITY_STORY_VIEWER, "setupListeners",
- // new Pair<>("swipeEvent", swipeEvent),
- // new Pair<>("diffX", diffX));
- if (BuildConfig.DEBUG) Log.e(TAG, "Error", e);
- }
- return false;
- }
- };
-
- if (hasFeedStories) {
- binding.btnBackward.setVisibility(currentFeedStoryIndex == 0 ? View.INVISIBLE : View.VISIBLE);
- binding.btnForward.setVisibility(currentFeedStoryIndex == finalModels.size() - 1 ? View.INVISIBLE : View.VISIBLE);
- binding.btnBackward.setOnClickListener(v -> paginateStories(finalModels.get(currentFeedStoryIndex - 1),
- finalModels.get(currentFeedStoryIndex),
- context, true, false));
- binding.btnForward.setOnClickListener(v -> paginateStories(finalModels.get(currentFeedStoryIndex + 1),
- finalModels.get(currentFeedStoryIndex),
- context, false,
- currentFeedStoryIndex == finalModels.size() - 2));
- }
-
- binding.imageViewer.setTapListener(simpleOnGestureListener);
- binding.spotify.setOnClickListener(v -> {
- final Object tag = v.getTag();
- if (tag instanceof CharSequence) {
- Utils.openURL(context, tag.toString());
- }
- });
- binding.swipeUp.setOnClickListener(v -> {
- final Object tag = v.getTag();
- if (tag instanceof CharSequence) {
- new AlertDialog.Builder(context)
- .setTitle(R.string.swipe_up_confirmation)
- .setMessage(tag.toString()).setPositiveButton(R.string.yes, (d, w) -> Utils.openURL(context, tag.toString()))
- .setNegativeButton(R.string.no, (d, w) -> d.dismiss()).show();
- }
- });
- binding.viewStoryPost.setOnClickListener(v -> {
- final Object tag = v.getTag();
- if (!(tag instanceof CharSequence)) return;
- final String mediaId = tag.toString();
- final AlertDialog alertDialog = new AlertDialog.Builder(context)
- .setCancelable(false)
- .setView(R.layout.dialog_opening_post)
- .create();
- alertDialog.show();
- mediaRepository.fetch(
- Long.parseLong(mediaId),
- CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- alertDialog.dismiss();
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- return;
- }
- final NavController navController = NavHostFragment.findNavController(StoryViewerFragment.this);
- final Bundle bundle = new Bundle();
- bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
- try {
- final NavDirections action = StoryViewerFragmentDirections.actionToPost(media, 0);
- navController.navigate(action);
- alertDialog.dismiss();
- } catch (Exception e) {
- Log.e(TAG, "openPostDialog: ", e);
- }
- }), Dispatchers.getIO())
- );
- });
- final View.OnClickListener storyActionListener = v -> {
- final Object tag = v.getTag();
- if (tag instanceof PollSticker) {
- poll = (PollSticker) tag;
- final List tallies = poll.getTallies();
- final String[] choices = tallies.stream()
- .map(t -> (poll.getViewerVote() != null && poll.getViewerVote() == tallies.indexOf(t) ? "√ " : "")
- + t.getText() + " (" + t.getCount() + ")" )
- .toArray(String[]::new);
- final ArrayAdapter adapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, choices);
- if (poll.getViewerVote() != null) {
- new AlertDialog.Builder(context)
- .setTitle(R.string.voted_story_poll)
- .setAdapter(adapter, null)
- .setPositiveButton(R.string.ok, null)
- .show();
- } else {
- new AlertDialog.Builder(context)
- .setTitle(poll.getQuestion())
- .setAdapter(adapter, (d, w) -> {
- sticking = true;
- storiesRepository.respondToPoll(
- csrfToken,
- userId,
- deviceId,
- currentStory.getId().split("_")[0],
- poll.getPollId(),
- w,
- CoroutineUtilsKt.getContinuation(
- (storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- sticking = false;
- Log.e(TAG, "Error responding", throwable);
- try {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- return;
- }
- sticking = false;
- try {
- poll.setViewerVote(w);
- Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- }),
- Dispatchers.getIO()
- )
- );
- })
- .setPositiveButton(R.string.cancel, null)
- .show();
- }
- } else if (tag instanceof QuestionSticker) {
- question = (QuestionSticker) tag;
- final EditText input = new EditText(context);
- input.setHint(R.string.answer_hint);
- final AlertDialog ad = new AlertDialog.Builder(context)
- .setTitle(question.getQuestion())
- .setView(input)
- .setPositiveButton(R.string.confirm, (d, w) -> {
- sticking = true;
- storiesRepository.respondToQuestion(
- csrfToken,
- userId,
- deviceId,
- currentStory.getId().split("_")[0],
- question.getQuestionId(),
- input.getText().toString(),
- CoroutineUtilsKt.getContinuation(
- (storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- sticking = false;
- Log.e(TAG, "Error responding", throwable);
- try {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- return;
- }
- sticking = false;
- try {
- Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- }),
- Dispatchers.getIO()
- )
- );
- })
- .setNegativeButton(R.string.cancel, null)
- .show();
- ad.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
- input.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {}
-
- @Override
- public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
- ad.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!TextUtils.isEmpty(s));
- }
-
- @Override
- public void afterTextChanged(final Editable s) {}
- });
- } else if (tag instanceof String[]) {
- final String[] rawMentions = (String[]) tag;
- mentions = new ArrayList(Arrays.asList(rawMentions));
- new AlertDialog.Builder(context)
- .setTitle(R.string.story_mentions)
- .setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, rawMentions), (d, w) -> openProfile(mentions.get(w)))
- .setPositiveButton(R.string.cancel, null)
- .show();
- } else if (tag instanceof QuizSticker) {
- quiz = (QuizSticker) tag;
- final List tallies = quiz.getTallies();
- final String[] choices = tallies.stream().map(
- t -> (quiz.getViewerAnswer() != null && quiz.getViewerAnswer() == tallies.indexOf(t) ? "√ " : "") +
- (quiz.getCorrectAnswer() == tallies.indexOf(t) ? "*** " : "") +
- t.getText() + " (" + t.getCount() + ")"
- ).toArray(String[]::new);
- new AlertDialog.Builder(context)
- .setTitle(quiz.getViewerAnswer() != null ? getString(R.string.story_quizzed) : quiz.getQuestion())
- .setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, choices), (d, w) -> {
- if (quiz.getViewerAnswer() == null) {
- sticking = true;
- storiesRepository.respondToQuiz(
- csrfToken,
- userId,
- deviceId,
- currentStory.getId().split("_")[0],
- quiz.getQuizId(),
- w,
- CoroutineUtilsKt.getContinuation(
- (storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- sticking = false;
- Log.e(TAG, "Error responding", throwable);
- try {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- return;
- }
- sticking = false;
- try {
- quiz.setViewerAnswer(w);
- Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- }),
- Dispatchers.getIO()
- )
- );
- }
- })
- .setPositiveButton(R.string.cancel, null)
- .show();
- } else if (tag instanceof SliderSticker) {
- slider = (SliderSticker) tag;
- NumberFormat percentage = NumberFormat.getPercentInstance();
- percentage.setMaximumFractionDigits(2);
- LinearLayout sliderView = new LinearLayout(context);
- sliderView.setLayoutParams(new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
- sliderView.setOrientation(LinearLayout.VERTICAL);
- TextView tv = new TextView(context);
- tv.setGravity(Gravity.CENTER_HORIZONTAL);
- final SeekBar input = new SeekBar(context);
- double avg = slider.getSliderVoteAverage() * 100;
- input.setProgress((int) avg);
- sliderView.addView(input);
- sliderView.addView(tv);
- if (slider.getViewerVote().isNaN() && slider.getViewerCanVote()) {
- input.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- sliderValue = progress / 100.0;
- tv.setText(percentage.format(sliderValue));
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- new AlertDialog.Builder(context)
- .setTitle(TextUtils.isEmpty(slider.getQuestion()) ? slider.getEmoji() : slider.getQuestion())
- .setMessage(getResources().getQuantityString(R.plurals.slider_info,
- slider.getSliderVoteCount(),
- slider.getSliderVoteCount(),
- percentage.format(slider.getSliderVoteAverage())))
- .setView(sliderView)
- .setPositiveButton(R.string.confirm, (d, w) -> {
- sticking = true;
- storiesRepository.respondToSlider(
- csrfToken,
- userId,
- deviceId,
- currentStory.getId().split("_")[0],
- slider.getSliderId(),
- sliderValue,
- CoroutineUtilsKt.getContinuation(
- (storyStickerResponse, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- sticking = false;
- Log.e(TAG, "Error responding", throwable);
- try {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- return;
- }
- sticking = false;
- try {
- slider.setViewerVote(sliderValue);
- Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
- } catch (Exception ignored) {}
- }), Dispatchers.getIO()
- )
- );
- })
- .setNegativeButton(R.string.cancel, null)
- .show();
- } else {
- input.setEnabled(false);
- tv.setText(getString(R.string.slider_answer, percentage.format(slider.getViewerVote())));
- new AlertDialog.Builder(context)
- .setTitle(TextUtils.isEmpty(slider.getQuestion()) ? slider.getEmoji() : slider.getQuestion())
- .setMessage(getResources().getQuantityString(R.plurals.slider_info,
- slider.getSliderVoteCount(),
- slider.getSliderVoteCount(),
- percentage.format(slider.getSliderVoteAverage())))
- .setView(sliderView)
- .setPositiveButton(R.string.ok, null)
- .show();
- }
- }
- };
- binding.poll.setOnClickListener(storyActionListener);
- binding.answer.setOnClickListener(storyActionListener);
- binding.mention.setOnClickListener(storyActionListener);
- binding.quiz.setOnClickListener(storyActionListener);
- binding.slider.setOnClickListener(storyActionListener);
- }
-
- private void resetView() {
- final Context context = getContext();
- if (context == null) return;
- live = null;
- slidePos = 0;
- lastSlidePos = 0;
- if (menuDownload != null) menuDownload.setVisible(false);
- if (menuDm != null) menuDm.setVisible(false);
- if (menuProfile != null) menuProfile.setVisible(false);
- downloadVisible = false;
- dmVisible = false;
- profileVisible = false;
- binding.imageViewer.setController(null);
- releasePlayer();
- String currentStoryMediaId = null;
- final Type type = options.getType();
- StoryViewerOptions fetchOptions = null;
- switch (type) {
- case HIGHLIGHT: {
- final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel;
- final List models = highlightsViewModel.getList().getValue();
- if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- return;
- }
- final Story model = models.get(currentFeedStoryIndex);
- currentStoryMediaId = model.getId();
- fetchOptions = StoryViewerOptions.forHighlight(model.getId());
- highlightTitle = model.getTitle();
- break;
- }
- case FEED_STORY_POSITION: {
- final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel;
- final List models = feedStoriesViewModel.getList().getValue();
- if (models == null || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0)
- return;
- final Story model = models.get(currentFeedStoryIndex);
- currentStoryMediaId = String.valueOf(model.getUser().getPk());
- currentStoryUsername = model.getUser().getUsername();
- fetchOptions = StoryViewerOptions.forUser(model.getUser().getPk(), currentStoryUsername);
- live = model.getBroadcast();
- break;
- }
- case STORY_ARCHIVE: {
- final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel;
- final List models = archivesViewModel.getList().getValue();
- if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- return;
- }
- final Story model = models.get(currentFeedStoryIndex);
- currentStoryMediaId = parseStoryMediaId(model.getId());
- currentStoryUsername = model.getTitle();
- fetchOptions = StoryViewerOptions.forStoryArchive(model.getId());
- break;
- }
- case USER: {
- currentStoryMediaId = String.valueOf(options.getId());
- currentStoryUsername = options.getName();
- fetchOptions = StoryViewerOptions.forUser(options.getId(), currentStoryUsername);
- break;
- }
- }
- setTitle(type);
- storiesViewModel.getList().setValue(Collections.emptyList());
- if (type == Type.STORY) {
- storiesRepository.fetch(
- options.getId(),
- CoroutineUtilsKt.getContinuation((storyModel, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Error", throwable);
- return;
- }
- fetching = false;
- binding.storiesList.setVisibility(View.GONE);
- if (storyModel == null) {
- storiesViewModel.getList().setValue(Collections.emptyList());
- currentStory = null;
- return;
- }
- storiesViewModel.getList().setValue(Collections.singletonList(storyModel));
- currentStory = storyModel;
- refreshStory();
- }), Dispatchers.getIO())
- );
- return;
- }
- if (currentStoryMediaId == null) return;
- if (live != null) {
- currentStory = null;
- refreshLive();
- return;
- }
- final ServiceCallback> storyCallback = new ServiceCallback>() {
- @Override
- public void onSuccess(final List storyModels) {
- fetching = false;
- if (storyModels == null || storyModels.isEmpty()) {
- storiesViewModel.getList().setValue(Collections.emptyList());
- currentStory = null;
- binding.storiesList.setVisibility(View.GONE);
- return;
- }
- binding.storiesList.setVisibility((storyModels.size() == 1 && currentFeedStoryIndex == -1) ? View.GONE : View.VISIBLE);
- if (currentFeedStoryIndex == -1) {
- binding.btnBackward.setVisibility(View.GONE);
- binding.btnForward.setVisibility(View.GONE);
- }
- storiesViewModel.getList().setValue(storyModels);
- currentStory = storyModels.get(0);
- refreshStory();
- }
-
- @Override
- public void onFailure(final Throwable t) {
- Log.e(TAG, "Error", t);
- }
- };
- storiesRepository.getStories(
- fetchOptions,
- CoroutineUtilsKt.getContinuation((storyModels, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
- if (throwable != null) {
- storyCallback.onFailure(throwable);
- return;
- }
- //noinspection unchecked
- storyCallback.onSuccess((List) storyModels);
- }), Dispatchers.getIO())
- );
- }
-
- private void setTitle(final Type type) {
- final boolean hasUsername = !TextUtils.isEmpty(currentStoryUsername);
- if (type == Type.HIGHLIGHT) {
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- if (actionBar != null) {
- actionBarTitle = highlightTitle;
- actionBar.setTitle(highlightTitle);
- }
- } else if (hasUsername) {
- currentStoryUsername = currentStoryUsername.replace("@", "");
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- if (actionBar != null) {
- actionBarTitle = currentStoryUsername;
- actionBar.setTitle(currentStoryUsername);
- }
- }
- }
-
- private synchronized void refreshLive() {
- binding.storiesList.setVisibility(View.INVISIBLE);
- binding.viewStoryPost.setVisibility(View.GONE);
- binding.spotify.setVisibility(View.GONE);
- binding.poll.setVisibility(View.GONE);
- binding.answer.setVisibility(View.GONE);
- binding.mention.setVisibility(View.GONE);
- binding.quiz.setVisibility(View.GONE);
- binding.slider.setVisibility(View.GONE);
- lastSlidePos = slidePos;
- releasePlayer();
- url = live.getDashPlaybackUrl();
- setupLive();
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- actionBarSubtitle = TextUtils.epochSecondToString(live.getPublishedTime());
- if (actionBar != null) {
- try {
- actionBar.setSubtitle(actionBarSubtitle);
- } catch (Exception e) {
- Log.e(TAG, "refreshLive: ", e);
- }
- }
- }
-
- private synchronized void refreshStory() {
- if (binding.storiesList.getVisibility() == View.VISIBLE) {
- final List storyModels = storiesViewModel.getList().getValue();
- if (storyModels != null && storyModels.size() > 0) {
- StoryMedia item = storyModels.get(lastSlidePos);
- if (item != null) {
- item.setCurrentSlide(false);
- storiesAdapter.notifyItemChanged(lastSlidePos, item);
- }
- item = storyModels.get(slidePos);
- if (item != null) {
- item.setCurrentSlide(true);
- storiesAdapter.notifyItemChanged(slidePos, item);
- }
- }
- }
- lastSlidePos = slidePos;
-
- final MediaItemType itemType = currentStory.getType();
-
- url = itemType == MediaItemType.MEDIA_TYPE_IMAGE
- ? ResponseBodyUtils.getImageUrl(currentStory)
- : ResponseBodyUtils.getVideoUrl(currentStory);
-
- if (currentStory.getStoryFeedMedia() != null) {
- final String shortCode = currentStory.getStoryFeedMedia().get(0).getMediaId();
- binding.viewStoryPost.setVisibility(View.VISIBLE);
- binding.viewStoryPost.setTag(shortCode);
- }
-
- final StoryAppAttribution spotify = currentStory.getStoryAppAttribution();
- if (spotify != null) {
- binding.spotify.setVisibility(View.VISIBLE);
- binding.spotify.setText(spotify.getName());
- binding.spotify.setTag(spotify.getContentUrl().split("?")[0]);
- }
-
- if (currentStory.getStoryPolls() != null) {
- poll = currentStory.getStoryPolls().get(0).getPollSticker();
- binding.poll.setVisibility(View.VISIBLE);
- binding.poll.setTag(poll);
- }
-
- if (currentStory.getStoryQuestions() != null) {
- question = currentStory.getStoryQuestions().get(0).getQuestionSticker();
- binding.answer.setVisibility(View.VISIBLE);
- binding.answer.setTag(question);
- }
-
- mentions.clear();
- if (currentStory.getReelMentions() != null) {
- mentions.addAll(currentStory.getReelMentions().stream().map(
- s -> s.getUser().getUsername()
- ).distinct().collect(Collectors.toList()));
- }
- if (currentStory.getStoryHashtags() != null) {
- mentions.addAll(currentStory.getStoryHashtags().stream().map(
- s -> s.getHashtag().getName()
- ).distinct().collect(Collectors.toList()));
- }
- if (currentStory.getStoryLocations() != null) {
- mentions.addAll(currentStory.getStoryLocations().stream().map(
- s -> s.getLocation().getShortName() + " (" + s.getLocation().getPk() + ")"
- ).distinct().collect(Collectors.toList()));
- }
- if (mentions.size() > 0) {
- binding.mention.setVisibility(View.VISIBLE);
- binding.mention.setTag(mentions.stream().toArray(String[]::new));
- }
-
- if (currentStory.getStoryQuizs() != null) {
- quiz = currentStory.getStoryQuizs().get(0).getQuizSticker();
- binding.quiz.setVisibility(View.VISIBLE);
- binding.quiz.setTag(quiz);
- }
-
- if (currentStory.getStorySliders() != null) {
- slider = currentStory.getStorySliders().get(0).getSliderSticker();
- binding.slider.setVisibility(View.VISIBLE);
- binding.slider.setTag(slider);
- }
-
- if (currentStory.getStoryCta() != null) {
- final StoryCta swipeUp = currentStory.getStoryCta().get(0).getLinks().get(0);
- binding.swipeUp.setVisibility(View.VISIBLE);
- binding.swipeUp.setText(currentStory.getLinkText());
- final String swipeUpUrl = swipeUp.getWebUri();
- final String actualLink = swipeUpUrl.startsWith("https://l.instagram.com/")
- ? Uri.parse(swipeUpUrl).getQueryParameter("u")
- : null;
- binding.swipeUp.setTag(actualLink == null && actualLink.startsWith("http")
- ? swipeUpUrl : actualLink);
- }
-
- releasePlayer();
- final Type type = options.getType();
- if (type == Type.HASHTAG || type == Type.LOCATION) {
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- if (actionBar != null) {
- actionBarTitle = currentStory.getUser().getUsername();
- actionBar.setTitle(currentStory.getUser().getUsername());
- }
- }
- if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
- else setupImage();
-
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- actionBarSubtitle = TextUtils.epochSecondToString(currentStory.getTakenAt());
- if (actionBar != null) {
- try {
- actionBar.setSubtitle(actionBarSubtitle);
- } catch (Exception e) {
- Log.e(TAG, "refreshStory: ", e);
- }
- }
-
- if (settingsHelper.getBoolean(MARK_AS_SEEN))
- storiesRepository.seen(
- csrfToken,
- userId,
- deviceId,
- currentStory.getId(),
- currentStory.getTakenAt(),
- System.currentTimeMillis() / 1000,
- CoroutineUtilsKt.getContinuation((s, throwable) -> {}, Dispatchers.getIO())
- );
- }
-
- private void removeStickers() {
- binding.swipeUp.setVisibility(View.GONE);
- binding.quiz.setVisibility(View.GONE);
- binding.spotify.setVisibility(View.GONE);
- binding.mention.setVisibility(View.GONE);
- binding.viewStoryPost.setVisibility(View.GONE);
- binding.answer.setVisibility(View.GONE);
- binding.slider.setVisibility(View.GONE);
- }
-
- private void downloadStory() {
- final Context context = getContext();
- if (context == null) return;
- if (currentStory == null) {
- Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
- return;
- }
- DownloadUtils.download(context, currentStory);
- }
-
- private void setupImage() {
- binding.progressView.setVisibility(View.VISIBLE);
- binding.playerView.setVisibility(View.GONE);
- binding.imageViewer.setVisibility(View.VISIBLE);
- final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
- .setLocalThumbnailPreviewsEnabled(true)
- .setProgressiveRenderingEnabled(true)
- .build();
- final DraweeController controller = Fresco.newDraweeControllerBuilder()
- .setImageRequest(requestBuilder)
- .setOldController(binding.imageViewer.getController())
- .setControllerListener(new BaseControllerListener() {
-
- @Override
- public void onFailure(final String id, final Throwable throwable) {
- binding.progressView.setVisibility(View.GONE);
- }
-
- @Override
- public void onFinalImageSet(final String id,
- final ImageInfo imageInfo,
- final Animatable animatable) {
- if (menuDownload != null) {
- downloadVisible = true;
- menuDownload.setVisible(true);
- }
- if (currentStory.getCanReply() && menuDm != null) {
- dmVisible = true;
- menuDm.setVisible(true);
- }
- if (!TextUtils.isEmpty(currentStory.getUser().getUsername())) {
- profileVisible = true;
- menuProfile.setVisible(true);
- }
- binding.progressView.setVisibility(View.GONE);
- }
- })
- .build();
- binding.imageViewer.setController(controller);
- }
-
- private void setupVideo() {
- binding.playerView.setVisibility(View.VISIBLE);
- binding.progressView.setVisibility(View.GONE);
- binding.imageViewer.setVisibility(View.GONE);
- binding.imageViewer.setController(null);
-
- final Context context = getContext();
- if (context == null) return;
- player = new SimpleExoPlayer.Builder(context).build();
- binding.playerView.setPlayer(player);
- player.setPlayWhenReady(settingsHelper.getBoolean(PreferenceKeys.AUTOPLAY_VIDEOS_STORIES));
-
- final Uri uri = Uri.parse(url);
- final MediaItem mediaItem = MediaItem.fromUri(uri);
- final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(context, "instagram"))
- .createMediaSource(mediaItem);
- mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
- @Override
- public void onLoadCompleted(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData) {
- if (menuDownload != null) {
- downloadVisible = true;
- menuDownload.setVisible(true);
- }
- if (currentStory.getCanReply() && menuDm != null) {
- dmVisible = true;
- menuDm.setVisible(true);
- }
- if (!TextUtils.isEmpty(currentStory.getUser().getUsername()) && menuProfile != null) {
- profileVisible = true;
- menuProfile.setVisible(true);
- }
- binding.progressView.setVisibility(View.GONE);
- }
-
- @Override
- public void onLoadStarted(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData) {
- if (menuDownload != null) {
- downloadVisible = true;
- menuDownload.setVisible(true);
- }
- if (currentStory.getCanReply() && menuDm != null) {
- dmVisible = true;
- menuDm.setVisible(true);
- }
- if (!TextUtils.isEmpty(currentStory.getUser().getUsername()) && menuProfile != null) {
- profileVisible = true;
- menuProfile.setVisible(true);
- }
- binding.progressView.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onLoadCanceled(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData) {
- binding.progressView.setVisibility(View.GONE);
- }
-
- @Override
- public void onLoadError(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData,
- @NonNull final IOException error,
- final boolean wasCanceled) {
- if (menuDownload != null) {
- downloadVisible = false;
- menuDownload.setVisible(false);
- }
- if (menuDm != null) {
- dmVisible = false;
- menuDm.setVisible(false);
- }
- if (menuProfile != null) {
- profileVisible = false;
- menuProfile.setVisible(false);
- }
- binding.progressView.setVisibility(View.GONE);
- }
- });
- player.setMediaSource(mediaSource);
- player.prepare();
-
- binding.playerView.setOnClickListener(v -> {
- if (player != null) {
- if (player.getPlaybackState() == Player.STATE_ENDED) player.seekTo(0);
- player.setPlayWhenReady(player.getPlaybackState() == Player.STATE_ENDED || !player.isPlaying());
- }
- });
- }
-
- private void setupLive() {
- binding.playerView.setVisibility(View.VISIBLE);
- binding.progressView.setVisibility(View.GONE);
- binding.imageViewer.setVisibility(View.GONE);
- binding.imageViewer.setController(null);
-
- if (menuDownload != null) menuDownload.setVisible(false);
- if (menuDm != null) menuDm.setVisible(false);
-
- final Context context = getContext();
- if (context == null) return;
- player = new SimpleExoPlayer.Builder(context).build();
- binding.playerView.setPlayer(player);
- player.setPlayWhenReady(settingsHelper.getBoolean(PreferenceKeys.AUTOPLAY_VIDEOS_STORIES));
-
- final Uri uri = Uri.parse(url);
- final MediaItem mediaItem = MediaItem.fromUri(uri);
- final DashMediaSource mediaSource = new DashMediaSource.Factory(new DefaultDataSourceFactory(context, "instagram"))
- .createMediaSource(mediaItem);
- mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
- @Override
- public void onLoadCompleted(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData) {
- binding.progressView.setVisibility(View.GONE);
- }
-
- @Override
- public void onLoadStarted(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData) {
- binding.progressView.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onLoadCanceled(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData) {
- binding.progressView.setVisibility(View.GONE);
- }
-
- @Override
- public void onLoadError(final int windowIndex,
- @Nullable final MediaSource.MediaPeriodId mediaPeriodId,
- @NonNull final LoadEventInfo loadEventInfo,
- @NonNull final MediaLoadData mediaLoadData,
- @NonNull final IOException error,
- final boolean wasCanceled) {
- binding.progressView.setVisibility(View.GONE);
- }
- });
- player.setMediaSource(mediaSource);
- player.prepare();
-
- binding.playerView.setOnClickListener(v -> {
- if (player != null) {
- if (player.getPlaybackState() == Player.STATE_ENDED) player.seekTo(0);
- player.setPlayWhenReady(player.getPlaybackState() == Player.STATE_ENDED || !player.isPlaying());
- }
- });
- }
-
- private void openProfile(final String username) {
- final ActionBar actionBar = fragmentActivity.getSupportActionBar();
- if (actionBar != null) {
- actionBar.setSubtitle(null);
- }
- final char t = username.charAt(0);
- if (t == '@') {
- final NavDirections action = HashTagFragmentDirections.actionToProfile().setUsername(username);
- NavHostFragment.findNavController(this).navigate(action);
- } else if (t == '#') {
- final NavDirections action = HashTagFragmentDirections.actionToHashtag(username.substring(1));
- NavHostFragment.findNavController(this).navigate(action);
- } else {
- final NavDirections action = ProfileFragmentDirections.actionToLocation(Long.parseLong(username.split(" \\(")[1].replace(")", "")));
- NavHostFragment.findNavController(this).navigate(action);
- }
- }
-
- private void releasePlayer() {
- if (player == null) return;
- try { player.stop(true); } catch (Exception ignored) { }
- try { player.release(); } catch (Exception ignored) { }
- player = null;
- }
-
- private void paginateStories(Object newFeedStory, Object oldFeedStory, Context context, boolean backward, boolean last) {
- if (newFeedStory != null) {
- if (fetching) {
- Toast.makeText(context, R.string.be_patient, Toast.LENGTH_SHORT).show();
- return;
- }
- if (settingsHelper.getBoolean(MARK_AS_SEEN)
- && oldFeedStory instanceof Story
- && viewModel instanceof FeedStoriesViewModel) {
- final FeedStoriesViewModel feedStoriesViewModel = (FeedStoriesViewModel) viewModel;
- final Story oldFeedStoryModel = (Story) oldFeedStory;
- if (oldFeedStoryModel.getSeen() == null || !oldFeedStoryModel.getSeen().equals(oldFeedStoryModel.getLatestReelMedia())) {
- oldFeedStoryModel.setSeen(oldFeedStoryModel.getLatestReelMedia());
- final List models = feedStoriesViewModel.getList().getValue();
- final List modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models);
- modelsCopy.set(currentFeedStoryIndex, oldFeedStoryModel);
- feedStoriesViewModel.getList().postValue(modelsCopy);
- }
- }
- fetching = true;
- binding.btnBackward.setVisibility(currentFeedStoryIndex == 1 && backward ? View.INVISIBLE : View.VISIBLE);
- binding.btnForward.setVisibility(last ? View.INVISIBLE : View.VISIBLE);
- currentFeedStoryIndex = backward ? (currentFeedStoryIndex - 1) : (currentFeedStoryIndex + 1);
- resetView();
- }
- }
-
- /**
- * Parses the Story's media ID. For user stories this is a number, but for archive stories
- * this is "archiveDay:" plus a number.
- */
- private static String parseStoryMediaId(String rawId) {
- final String regex = "(?:archiveDay:)?(.+)";
- final Pattern pattern = Pattern.compile(regex);
- final Matcher matcher = pattern.matcher(rawId);
-
- if (matcher.matches() && matcher.groupCount() >= 1) {
- return matcher.group(1);
- }
-
- return rawId;
- }
-}
diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.kt b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.kt
new file mode 100644
index 00000000..40362e0c
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.kt
@@ -0,0 +1,905 @@
+package awais.instagrabber.fragments
+
+import android.annotation.SuppressLint
+import android.content.DialogInterface.OnClickListener
+import android.graphics.drawable.Animatable
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.util.Log
+import android.view.*
+import android.view.GestureDetector.SimpleOnGestureListener
+import android.widget.*
+import android.widget.SeekBar.OnSeekBarChangeListener
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.view.ContextThemeWrapper
+import androidx.appcompat.widget.PopupMenu
+import androidx.core.view.GestureDetectorCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.Observer
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.NavController
+import androidx.navigation.fragment.NavHostFragment
+import androidx.recyclerview.widget.LinearLayoutManager
+import awais.instagrabber.BuildConfig
+import awais.instagrabber.R
+import awais.instagrabber.adapters.StoriesAdapter
+import awais.instagrabber.customviews.helpers.SwipeGestureListener
+import awais.instagrabber.databinding.FragmentStoryViewerBinding
+import awais.instagrabber.fragments.main.ProfileFragment
+import awais.instagrabber.fragments.settings.PreferenceKeys
+import awais.instagrabber.interfaces.SwipeEvent
+import awais.instagrabber.models.Resource
+import awais.instagrabber.models.enums.FavoriteType
+import awais.instagrabber.models.enums.MediaItemType
+import awais.instagrabber.models.enums.StoryPaginationType
+import awais.instagrabber.repositories.requests.StoryViewerOptions
+import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
+import awais.instagrabber.repositories.responses.stories.*
+import awais.instagrabber.utils.Constants
+import awais.instagrabber.utils.DownloadUtils.download
+import awais.instagrabber.utils.TextUtils.epochSecondToString
+import awais.instagrabber.utils.ResponseBodyUtils
+import awais.instagrabber.utils.Utils
+import awais.instagrabber.utils.extensions.TAG
+import awais.instagrabber.viewmodels.ArchivesViewModel
+import awais.instagrabber.viewmodels.FeedStoriesViewModel
+import awais.instagrabber.viewmodels.StoryFragmentViewModel
+import awais.instagrabber.webservices.MediaRepository
+import awais.instagrabber.webservices.StoriesRepository
+import com.facebook.drawee.backends.pipeline.Fresco
+import com.facebook.drawee.controller.BaseControllerListener
+import com.facebook.drawee.interfaces.DraweeController
+import com.facebook.imagepipeline.image.ImageInfo
+import com.facebook.imagepipeline.request.ImageRequestBuilder
+import com.google.android.exoplayer2.MediaItem
+import com.google.android.exoplayer2.Player
+import com.google.android.exoplayer2.SimpleExoPlayer
+import com.google.android.exoplayer2.source.*
+import com.google.android.exoplayer2.source.dash.DashMediaSource
+import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
+import com.google.android.material.textfield.TextInputEditText
+import java.io.IOException
+import java.text.NumberFormat
+import java.util.*
+
+
+class StoryViewerFragment : Fragment() {
+ private val TAG = "StoryViewerFragment"
+
+ private var root: View? = null
+ private var currentStoryUsername: String? = null
+ private var storiesAdapter: StoriesAdapter? = null
+ private var swipeEvent: SwipeEvent? = null
+ private var gestureDetector: GestureDetectorCompat? = null
+ private val storiesRepository: StoriesRepository? = null
+ private val mediaRepository: MediaRepository? = null
+ private var live: Broadcast? = null
+ private var menuProfile: MenuItem? = null
+ private var profileVisible: Boolean = false
+ private var player: SimpleExoPlayer? = null
+
+ private var actionBarTitle: String? = null
+ private var actionBarSubtitle: String? = null
+ private var shouldRefresh = true
+ private var currentFeedStoryIndex = 0
+ private var sliderValue = 0.0
+ private var options: StoryViewerOptions? = null
+ private var listViewModel: ViewModel? = null
+ private var backStackSavedStateResultLiveData: MutableLiveData? = null
+ private lateinit var fragmentActivity: AppCompatActivity
+ private lateinit var storiesViewModel: StoryFragmentViewModel
+ private lateinit var binding: FragmentStoryViewerBinding
+
+ @Suppress("UNCHECKED_CAST")
+ private val backStackSavedStateObserver = Observer { result ->
+ if (result == null) return@Observer
+ if ((result is RankedRecipient)) {
+ if (context != null) {
+ Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show()
+ }
+ storiesViewModel.shareDm(result)
+ } else if ((result is Set<*>)) {
+ try {
+ if (context != null) {
+ Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show()
+ }
+ storiesViewModel.shareDm(result as Set)
+ } catch (e: Exception) {
+ Log.e(TAG, "share: ", e)
+ }
+ }
+ // clear result
+ backStackSavedStateResultLiveData?.postValue(null)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ fragmentActivity = requireActivity() as AppCompatActivity
+ storiesViewModel = ViewModelProvider(this).get(StoryFragmentViewModel::class.java)
+ setHasOptionsMenu(true)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ if (root != null) {
+ shouldRefresh = false
+ return root
+ }
+ binding = FragmentStoryViewerBinding.inflate(inflater, container, false)
+ root = binding.root
+ return root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ if (!shouldRefresh) return
+ init()
+ shouldRefresh = false
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.story_menu, menu)
+ menuProfile = menu.findItem(R.id.action_profile)
+ menuProfile!!.isVisible = profileVisible
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val itemId = item.itemId
+ if (itemId == R.id.action_profile) {
+ val username = storiesViewModel.getCurrentStory().value?.user?.username
+ openProfile(Pair(username, FavoriteType.USER))
+ return true
+ }
+ return false
+ }
+
+ override fun onPause() {
+ super.onPause()
+ player?.pause() ?: return
+ }
+
+ override fun onResume() {
+ super.onResume()
+ setHasOptionsMenu(true)
+ try {
+ val backStackEntry = NavHostFragment.findNavController(this).currentBackStackEntry
+ if (backStackEntry != null) {
+ backStackSavedStateResultLiveData = backStackEntry.savedStateHandle.getLiveData("result")
+ backStackSavedStateResultLiveData?.observe(viewLifecycleOwner, backStackSavedStateObserver)
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "onResume: ", e)
+ }
+ val actionBar = fragmentActivity.supportActionBar ?: return
+ actionBar.title = storiesViewModel.getTitle().value
+ actionBar.subtitle = storiesViewModel.getDate().value
+ }
+
+ override fun onDestroy() {
+ releasePlayer()
+ val actionBar = fragmentActivity.supportActionBar
+ actionBar?.subtitle = null
+ super.onDestroy()
+ }
+
+ private fun init() {
+ val args = arguments ?: return
+ val fragmentArgs = StoryViewerFragmentArgs.fromBundle(args)
+ options = fragmentArgs.options
+ currentFeedStoryIndex = options!!.currentFeedStoryIndex
+ val type = options!!.type
+ if (currentFeedStoryIndex >= 0) {
+ listViewModel = when (type) {
+ StoryViewerOptions.Type.STORY_ARCHIVE ->
+ ViewModelProvider(fragmentActivity).get(ArchivesViewModel::class.java)
+ StoryViewerOptions.Type.FEED_STORY_POSITION ->
+ ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel::class.java)
+ else -> null
+ }
+ }
+ setupButtons()
+ setupStories()
+ }
+
+ private fun setupStories() {
+ setupListeners()
+ val context = context ?: return
+ binding.storiesList.layoutManager =
+ LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+ storiesAdapter = StoriesAdapter { _, position ->
+ storiesViewModel.setMedia(position)
+ }
+ binding.storiesList.adapter = storiesAdapter
+ storiesViewModel.getCurrentStory().observe(fragmentActivity, {
+ if (it?.items != null) {
+ val storyMedias = it.items.toMutableList()
+ val newItem = storyMedias.get(0)
+ newItem.isCurrentSlide = true
+ storyMedias.set(0, newItem)
+ storiesAdapter!!.submitList(storyMedias)
+ storiesViewModel.setMedia(0)
+ binding.listToggle.isEnabled = true
+ binding.storiesList.visibility = if (Utils.settingsHelper.getBoolean(PreferenceKeys.PREF_STORY_SHOW_LIST)) View.VISIBLE
+ else View.GONE
+ }
+ else {
+ binding.listToggle.isEnabled = false
+ binding.storiesList.visibility = View.GONE
+ }
+ })
+ storiesViewModel.getDate().observe(fragmentActivity, {
+ val actionBar = fragmentActivity.supportActionBar
+ if (actionBar != null && it != null) actionBar.subtitle = it
+ })
+ storiesViewModel.getTitle().observe(fragmentActivity, {
+ val actionBar = fragmentActivity.supportActionBar
+ if (actionBar != null && it != null) actionBar.title = it
+ })
+ storiesViewModel.getCurrentMedia().observe(fragmentActivity, { refreshStory(it) })
+ storiesViewModel.getCurrentIndex().observe(fragmentActivity, {
+ storiesAdapter!!.paginate(it)
+ })
+ storiesViewModel.getOptions().observe(fragmentActivity, {
+ binding.stickers.isEnabled = it.first.size > 0
+ })
+ }
+
+ private fun setupButtons() {
+ binding.btnDownload.setOnClickListener({ _ -> downloadStory() })
+ binding.btnForward.setOnClickListener({ _ -> storiesViewModel.skip(false) })
+ binding.btnBackward.setOnClickListener({ _ -> storiesViewModel.skip(true) })
+ binding.btnShare.setOnClickListener({ _ -> shareStoryViaDm() })
+ binding.btnReply.setOnClickListener({ _ -> createReplyDialog(null) })
+ binding.stickers.setOnClickListener({ _ -> showStickerMenu() })
+ binding.listToggle.setOnClickListener({ _ ->
+ binding.storiesList.visibility = if (binding.storiesList.visibility == View.GONE) View.VISIBLE
+ else View.GONE
+ })
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ private fun setupListeners() {
+ var liveModels: LiveData?>? = null
+ if (currentFeedStoryIndex >= 0) {
+ val type = options!!.type
+ when (type) {
+ StoryViewerOptions.Type.HIGHLIGHT -> {
+ storiesViewModel.fetchHighlights(options!!.id)
+ liveModels = storiesViewModel.getHighlights()
+ }
+ StoryViewerOptions.Type.FEED_STORY_POSITION -> {
+ val feedStoriesViewModel = listViewModel as FeedStoriesViewModel?
+ liveModels = feedStoriesViewModel!!.list
+ }
+ StoryViewerOptions.Type.STORY_ARCHIVE -> {
+ val archivesViewModel = listViewModel as ArchivesViewModel?
+ liveModels = archivesViewModel!!.list
+ }
+ StoryViewerOptions.Type.USER -> {
+ resetView()
+ }
+ }
+ }
+ if (liveModels != null) liveModels.observe(viewLifecycleOwner, { models ->
+ storiesViewModel.getPagination().observe(fragmentActivity, {
+ if (models != null) {
+ when (it) {
+ StoryPaginationType.FORWARD -> {
+ if (currentFeedStoryIndex == models.size - 1)
+ Toast.makeText(
+ context,
+ R.string.no_more_stories,
+ Toast.LENGTH_SHORT
+ ).show()
+ else paginateStories(false, currentFeedStoryIndex == models.size - 2)
+ }
+ StoryPaginationType.BACKWARD -> {
+ if (currentFeedStoryIndex == 0)
+ Toast.makeText(
+ context,
+ R.string.no_more_stories,
+ Toast.LENGTH_SHORT
+ ).show()
+ else paginateStories(true, false)
+ }
+ StoryPaginationType.ERROR -> {
+ Toast.makeText(
+ context,
+ R.string.downloader_unknown_error,
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ })
+ if (models != null && !models.isEmpty()) {
+ binding.btnBackward.isEnabled = currentFeedStoryIndex != 0
+ binding.btnForward.isEnabled = currentFeedStoryIndex != models.size - 1
+ resetView()
+ }
+ })
+
+ val context = context ?: return
+ swipeEvent = SwipeEvent { isRightSwipe: Boolean ->
+ storiesViewModel.paginate(isRightSwipe)
+ }
+ gestureDetector = GestureDetectorCompat(context, SwipeGestureListener(swipeEvent))
+ binding.playerView.setOnTouchListener { _, event -> gestureDetector!!.onTouchEvent(event) }
+ val simpleOnGestureListener: SimpleOnGestureListener = object : SimpleOnGestureListener() {
+ override fun onFling(
+ e1: MotionEvent,
+ e2: MotionEvent,
+ velocityX: Float,
+ velocityY: Float
+ ): Boolean {
+ val diffX = e2.x - e1.x
+ try {
+ if (Math.abs(diffX) > Math.abs(e2.y - e1.y) && Math.abs(diffX) > SwipeGestureListener.SWIPE_THRESHOLD && Math.abs(
+ velocityX
+ ) > SwipeGestureListener.SWIPE_VELOCITY_THRESHOLD
+ ) {
+ storiesViewModel.paginate(diffX > 0)
+ return true
+ }
+ } catch (e: Exception) {
+ if (BuildConfig.DEBUG) Log.e(TAG, "Error", e)
+ }
+ return false
+ }
+ }
+ binding.imageViewer.setTapListener(simpleOnGestureListener)
+ }
+
+ private fun resetView() {
+ val context = context ?: return
+ live = null
+ if (menuProfile != null) menuProfile!!.isVisible = false
+ binding.imageViewer.controller = null
+ releasePlayer()
+ val type = options!!.type
+ var fetchOptions: StoryViewerOptions? = null
+ when (type) {
+ StoryViewerOptions.Type.HIGHLIGHT -> {
+ val models = storiesViewModel.getHighlights().value
+ if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size || currentFeedStoryIndex < 0) {
+ Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show()
+ return
+ }
+ fetchOptions = StoryViewerOptions.forHighlight(0L, models[currentFeedStoryIndex].id)
+ }
+ StoryViewerOptions.Type.FEED_STORY_POSITION -> {
+ val feedStoriesViewModel = listViewModel as FeedStoriesViewModel?
+ val models = feedStoriesViewModel!!.list.value
+ if (models == null || currentFeedStoryIndex >= models.size || currentFeedStoryIndex < 0) return
+ val (_, _, _, _, user, _, _, _, _, _, _, broadcast) = models[currentFeedStoryIndex]
+ currentStoryUsername = user!!.username
+ fetchOptions = StoryViewerOptions.forUser(user.pk, currentStoryUsername)
+ live = broadcast
+ }
+ StoryViewerOptions.Type.STORY_ARCHIVE -> {
+ val archivesViewModel = listViewModel as ArchivesViewModel?
+ val models = archivesViewModel!!.list.value
+ if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size || currentFeedStoryIndex < 0) {
+ Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT)
+ .show()
+ return
+ }
+ val (id, _, _, _, _, _, _, _, _, title) = models[currentFeedStoryIndex]
+ currentStoryUsername = title
+ fetchOptions = StoryViewerOptions.forStoryArchive(id)
+ }
+ StoryViewerOptions.Type.USER -> {
+ currentStoryUsername = options!!.name
+ fetchOptions = StoryViewerOptions.forUser(options!!.id, currentStoryUsername)
+ }
+ }
+ if (type == StoryViewerOptions.Type.STORY) {
+ storiesViewModel.fetchSingleMedia(options!!.id)
+ return
+ }
+ if (live != null) {
+ refreshLive()
+ return
+ }
+ storiesViewModel.fetchStory(fetchOptions).observe(fragmentActivity, {
+ if (it.status == Resource.Status.ERROR) {
+ Toast.makeText(context, "Error: " + it.message, Toast.LENGTH_SHORT).show()
+ }
+ })
+ }
+
+ @Synchronized
+ private fun refreshLive() {
+ releasePlayer()
+ setupLive(live!!.dashPlaybackUrl ?: live!!.dashAbrPlaybackUrl ?: return)
+ val actionBar = fragmentActivity.supportActionBar
+ actionBarSubtitle = epochSecondToString(live!!.publishedTime!!)
+ if (actionBar != null) {
+ try {
+ actionBar.setSubtitle(actionBarSubtitle)
+ } catch (e: Exception) {
+ Log.e(TAG, "refreshLive: ", e)
+ }
+ }
+ }
+
+ @Synchronized
+ private fun refreshStory(currentStory: StoryMedia) {
+ val itemType = currentStory.type
+ val url = if (itemType === MediaItemType.MEDIA_TYPE_IMAGE) ResponseBodyUtils.getImageUrl(currentStory)
+ else ResponseBodyUtils.getVideoUrl(currentStory)
+
+ releasePlayer()
+
+ profileVisible = currentStory.user?.username != null
+ if (menuProfile != null) menuProfile!!.isVisible = profileVisible
+
+ binding.btnDownload.isEnabled = false
+ binding.btnShare.isEnabled = currentStory.canReshare
+ binding.btnReply.isEnabled = currentStory.canReply
+ if (itemType === MediaItemType.MEDIA_TYPE_VIDEO) setupVideo(url) else setupImage(url)
+
+// if (Utils.settingsHelper.getBoolean(MARK_AS_SEEN)) storiesRepository!!.seen(
+// csrfToken,
+// userId,
+// deviceId,
+// currentStory!!.id!!,
+// currentStory!!.takenAt,
+// System.currentTimeMillis() / 1000
+// )
+ }
+
+ private fun downloadStory() {
+ val context = context ?: return
+ val currentStory = storiesViewModel.getMedia().value
+ if (currentStory == null) {
+ Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show()
+ return
+ }
+ download(context, currentStory)
+ }
+
+ private fun setupImage(url: String) {
+ binding.progressView.visibility = View.VISIBLE
+ binding.playerView.visibility = View.GONE
+ binding.imageViewer.visibility = View.VISIBLE
+ val requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
+ .setLocalThumbnailPreviewsEnabled(true)
+ .setProgressiveRenderingEnabled(true)
+ .build()
+ val controller: DraweeController = Fresco.newDraweeControllerBuilder()
+ .setImageRequest(requestBuilder)
+ .setOldController(binding.imageViewer.controller)
+ .setControllerListener(object : BaseControllerListener() {
+ override fun onFailure(id: String, throwable: Throwable) {
+ binding.btnDownload.isEnabled = false
+ binding.progressView.visibility = View.GONE
+ }
+
+ override fun onFinalImageSet(
+ id: String,
+ imageInfo: ImageInfo?,
+ animatable: Animatable?
+ ) {
+ binding.btnDownload.isEnabled = true
+ binding.progressView.visibility = View.GONE
+ }
+ })
+ .build()
+ binding.imageViewer.controller = controller
+ }
+
+ private fun setupVideo(url: String) {
+ binding.playerView.visibility = View.VISIBLE
+ binding.progressView.visibility = View.GONE
+ binding.imageViewer.visibility = View.GONE
+ binding.imageViewer.controller = null
+ val context = context ?: return
+ player = SimpleExoPlayer.Builder(context).build()
+ binding.playerView.player = player
+ player!!.playWhenReady =
+ Utils.settingsHelper.getBoolean(PreferenceKeys.AUTOPLAY_VIDEOS_STORIES)
+ val uri = Uri.parse(url)
+ val mediaItem = MediaItem.fromUri(uri)
+ val mediaSource =
+ ProgressiveMediaSource.Factory(DefaultDataSourceFactory(context, "instagram"))
+ .createMediaSource(mediaItem)
+ mediaSource.addEventListener(Handler(), object : MediaSourceEventListener {
+ override fun onLoadCompleted(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData
+ ) {
+ binding.btnDownload.isEnabled = true
+ binding.progressView.visibility = View.GONE
+ }
+
+ override fun onLoadStarted(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData
+ ) {
+ binding.btnDownload.isEnabled = true
+ binding.progressView.visibility = View.VISIBLE
+ }
+
+ override fun onLoadCanceled(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData
+ ) {
+ binding.progressView.visibility = View.GONE
+ }
+
+ override fun onLoadError(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData,
+ error: IOException,
+ wasCanceled: Boolean
+ ) {
+ binding.btnDownload.isEnabled = false
+ binding.progressView.visibility = View.GONE
+ }
+ })
+ player!!.setMediaSource(mediaSource)
+ player!!.prepare()
+ binding.playerView.setOnClickListener { _ ->
+ if (player != null) {
+ if (player!!.playbackState == Player.STATE_ENDED) player!!.seekTo(0)
+ player!!.playWhenReady =
+ player!!.playbackState == Player.STATE_ENDED || !player!!.isPlaying
+ }
+ }
+ }
+
+ private fun setupLive(url: String) {
+ binding.playerView.visibility = View.VISIBLE
+ binding.progressView.visibility = View.GONE
+ binding.imageViewer.visibility = View.GONE
+ binding.imageViewer.controller = null
+ val context = context ?: return
+ player = SimpleExoPlayer.Builder(context).build()
+ binding.playerView.player = player
+ player!!.playWhenReady =
+ Utils.settingsHelper.getBoolean(PreferenceKeys.AUTOPLAY_VIDEOS_STORIES)
+ val uri = Uri.parse(url)
+ val mediaItem = MediaItem.fromUri(uri)
+ val mediaSource = DashMediaSource.Factory(DefaultDataSourceFactory(context, "instagram"))
+ .createMediaSource(mediaItem)
+ mediaSource.addEventListener(Handler(), object : MediaSourceEventListener {
+ override fun onLoadCompleted(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData
+ ) {
+ binding.progressView.visibility = View.GONE
+ }
+
+ override fun onLoadStarted(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData
+ ) {
+ binding.progressView.visibility = View.VISIBLE
+ }
+
+ override fun onLoadCanceled(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData
+ ) {
+ binding.progressView.visibility = View.GONE
+ }
+
+ override fun onLoadError(
+ windowIndex: Int,
+ mediaPeriodId: MediaSource.MediaPeriodId?,
+ loadEventInfo: LoadEventInfo,
+ mediaLoadData: MediaLoadData,
+ error: IOException,
+ wasCanceled: Boolean
+ ) {
+ binding.progressView.visibility = View.GONE
+ }
+ })
+ player!!.setMediaSource(mediaSource)
+ player!!.prepare()
+ binding.playerView.setOnClickListener { _ ->
+ if (player != null) {
+ if (player!!.playbackState == Player.STATE_ENDED) player!!.seekTo(0)
+ player!!.playWhenReady =
+ player!!.playbackState == Player.STATE_ENDED || !player!!.isPlaying
+ }
+ }
+ }
+
+ private fun openProfile(data: Pair) {
+ val navController: NavController = NavHostFragment.findNavController(this)
+ val bundle = Bundle()
+ if (data.first == null) {
+ // toast
+ return
+ }
+ val actionBar = fragmentActivity.supportActionBar
+ if (actionBar != null) {
+ actionBar.title = null
+ actionBar.subtitle = null
+ }
+ when (data.second) {
+ FavoriteType.USER -> {
+ bundle.putString("username", data.first)
+ navController.navigate(R.id.action_global_profileFragment, bundle)
+ }
+ FavoriteType.HASHTAG -> {
+ bundle.putString("hashtag", data.first)
+ navController.navigate(R.id.action_global_hashTagFragment, bundle)
+ }
+ FavoriteType.LOCATION -> {
+ bundle.putLong("locationId", data.first!!.toLong())
+ navController.navigate(R.id.action_global_locationFragment, bundle)
+ }
+ }
+ }
+
+ private fun releasePlayer() {
+ if (player == null) return
+ try {
+ player!!.stop(true)
+ } catch (ignored: Exception) {
+ }
+ try {
+ player!!.release()
+ } catch (ignored: Exception) {
+ }
+ player = null
+ }
+
+ private fun paginateStories(
+ backward: Boolean,
+ last: Boolean
+ ) {
+ binding.btnBackward.isEnabled = currentFeedStoryIndex != 1 || !backward
+ binding.btnForward.isEnabled = !last
+ currentFeedStoryIndex = if (backward) currentFeedStoryIndex - 1 else currentFeedStoryIndex + 1
+ resetView()
+ }
+
+ private fun createChoiceDialog(
+ title: String?,
+ tallies: List,
+ onClickListener: OnClickListener,
+ viewerVote: Int?,
+ correctAnswer: Int?
+ ) {
+ val context = context ?: return
+ val choices = tallies.map {
+ (if (viewerVote == tallies.indexOf(it)) "√ " else "") +
+ (if (correctAnswer == tallies.indexOf(it)) "*** " else "") +
+ it.text + " (" + it.count + ")" }
+ val builder = AlertDialog.Builder(context)
+ if (title != null) builder.setTitle(title)
+ if (viewerVote != null) builder.setMessage(R.string.story_quizzed)
+ builder.setPositiveButton(if (viewerVote == null) R.string.cancel else R.string.ok, null)
+ val adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, choices.toTypedArray())
+ builder.setAdapter(adapter, onClickListener)
+ builder.show()
+ }
+
+ private fun createMentionDialog() {
+ val context = context ?: return
+ val adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, storiesViewModel.getMentionTexts())
+ val builder = AlertDialog.Builder(context)
+ .setPositiveButton(R.string.ok, null)
+ .setAdapter(adapter, { _, w ->
+ val data = storiesViewModel.getMention(w)
+ if (data != null) openProfile(Pair(data.second, data.third))
+ })
+ builder.show()
+ }
+
+ private fun createSliderDialog() {
+ val slider = storiesViewModel.getSlider().value ?: return
+ val context = context ?: return
+ val percentage: NumberFormat = NumberFormat.getPercentInstance()
+ percentage.maximumFractionDigits = 2
+ val sliderView = LinearLayout(context)
+ sliderView.layoutParams = LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ sliderView.orientation = LinearLayout.VERTICAL
+ val tv = TextView(context)
+ tv.gravity = Gravity.CENTER_HORIZONTAL
+ val input = SeekBar(context)
+ val avg: Double = slider.sliderVoteAverage ?: 0.5
+ input.progress = (avg * 100).toInt()
+ var onClickListener: OnClickListener? = null
+
+ if (slider.viewerVote == null && slider.viewerCanVote == true) {
+ input.isEnabled = true
+ input.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ sliderValue = progress / 100.0
+ tv.text = percentage.format(sliderValue)
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar) {}
+ })
+ onClickListener = OnClickListener { _, _ -> storiesViewModel.answerSlider(sliderValue) }
+ }
+ else {
+ input.isEnabled = false
+ tv.text = getString(R.string.slider_answer, percentage.format(slider.viewerVote))
+ }
+ sliderView.addView(input)
+ sliderView.addView(tv)
+ val builder = AlertDialog.Builder(context)
+ .setTitle(if (slider.question.isNullOrEmpty()) slider.emoji else slider.question)
+ .setMessage(
+ resources.getQuantityString(R.plurals.slider_info,
+ slider.sliderVoteCount ?: 0,
+ slider.sliderVoteCount ?: 0,
+ percentage.format(avg)))
+ .setView(sliderView)
+ .setPositiveButton(R.string.ok, onClickListener)
+
+ builder.show()
+ }
+
+ private fun createReplyDialog(question: String?) {
+ val context = context ?: return
+ val input = TextInputEditText(context)
+ input.setHint(R.string.reply_hint)
+ val builder = AlertDialog.Builder(context)
+ .setTitle(question ?: context.getString(R.string.reply_story))
+ .setView(input)
+ val onClickListener = OnClickListener{ _, _ ->
+ val result =
+ if (question != null) storiesViewModel.answerQuestion(input.text.toString())
+ else storiesViewModel.reply(input.text.toString())
+ if (result == null) {
+ Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT)
+ .show()
+ }
+ else result.observe(viewLifecycleOwner, {
+ when (it.status) {
+ Resource.Status.SUCCESS -> {
+ Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT)
+ .show()
+ }
+ Resource.Status.ERROR -> {
+ Toast.makeText(context, "Error: " + it.message, Toast.LENGTH_SHORT)
+ .show()
+ }
+ Resource.Status.LOADING -> {
+ Toast.makeText(context, R.string.sending, Toast.LENGTH_SHORT).show()
+ }
+ }
+ })
+ }
+ builder.setPositiveButton(R.string.confirm, onClickListener)
+ builder.show()
+ }
+
+ private fun shareStoryViaDm() {
+ val actionGlobalUserSearch = UserSearchFragmentDirections.actionGlobalUserSearch().apply {
+ title = getString(R.string.share)
+ setActionLabel(getString(R.string.send))
+ showGroups = true
+ multiple = true
+ setSearchMode(UserSearchFragment.SearchMode.RAVEN)
+ }
+ try {
+ val navController = NavHostFragment.findNavController(this@StoryViewerFragment)
+ navController.navigate(actionGlobalUserSearch)
+ } catch (e: Exception) {
+ Log.e(TAG, "shareStoryViaDm: ", e)
+ }
+ }
+
+ private fun showStickerMenu() {
+ val data = storiesViewModel.getOptions().value
+ if (data == null) return
+ val themeWrapper = ContextThemeWrapper(context, R.style.popupMenuStyle)
+ val popupMenu = PopupMenu(themeWrapper, binding.stickers)
+ val menu = popupMenu.menu
+ data.first.map {
+ if (it.second != 0) menu.add(0, it.first, 0, it.second)
+ if (it.first == R.id.swipeUp) menu.add(0, R.id.swipeUp, 0, data.second)
+ if (it.first == R.id.spotify) menu.add(0, R.id.spotify, 0, data.third)
+ }
+ popupMenu.setOnMenuItemClickListener { item: MenuItem ->
+ val itemId = item.itemId
+ if (itemId == R.id.spotify) openExternalLink(storiesViewModel.getAppAttribution())
+ else if (itemId == R.id.swipeUp) openExternalLink(storiesViewModel.getSwipeUp())
+ else if (itemId == R.id.mentions) createMentionDialog()
+ else if (itemId == R.id.slider) createSliderDialog()
+ else if (itemId == R.id.question) {
+ val question = storiesViewModel.getQuestion().value
+ if (question != null) createReplyDialog(question.question)
+ }
+ else if (itemId == R.id.quiz) {
+ val quiz = storiesViewModel.getQuiz().value
+ if (quiz != null) createChoiceDialog(
+ quiz.question,
+ quiz.tallies,
+ { _, w -> storiesViewModel.answerQuiz(w) },
+ quiz.viewerAnswer,
+ quiz.correctAnswer
+ )
+ }
+ else if (itemId == R.id.poll) {
+ val poll = storiesViewModel.getPoll().value
+ if (poll != null) createChoiceDialog(
+ poll.question,
+ poll.tallies,
+ { _, w -> storiesViewModel.answerPoll(w) },
+ poll.viewerVote,
+ null
+ )
+ }
+ else if (itemId == R.id.viewStoryPost) {
+ storiesViewModel.getLinkedPost().observe(viewLifecycleOwner, {
+ if (it == null) Toast.makeText(context, "Error: LiveData is null", Toast.LENGTH_SHORT).show()
+ else when (it.status) {
+ Resource.Status.SUCCESS -> {
+ if (it.data != null) {
+ val actionBar = fragmentActivity.supportActionBar
+ if (actionBar != null) {
+ actionBar.title = null
+ actionBar.subtitle = null
+ }
+ val navController =
+ NavHostFragment.findNavController(this@StoryViewerFragment)
+ val bundle = Bundle()
+ bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, it.data)
+ try {
+ navController.navigate(R.id.action_global_post_view, bundle)
+ } catch (e: Exception) {
+ Log.e(TAG, "openPostDialog: ", e)
+ }
+ }
+ }
+ Resource.Status.ERROR -> {
+ Toast.makeText(context, "Error: " + it.message, Toast.LENGTH_SHORT)
+ .show()
+ }
+ Resource.Status.LOADING -> {
+ Toast.makeText(context, R.string.opening_post, Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+ })
+ }
+ false
+ }
+ popupMenu.show()
+ }
+
+ private fun openExternalLink(url: String?) {
+ val context = context ?: return
+ if (url == null) return
+ AlertDialog.Builder(context)
+ .setTitle(R.string.swipe_up_confirmation)
+ .setMessage(url).setPositiveButton(R.string.yes, { _, _ -> Utils.openURL(context, url) })
+ .setNegativeButton(R.string.no, null)
+ .show()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt
index d5708533..3eb27b33 100644
--- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt
+++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt
@@ -209,7 +209,7 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
}
}
private val onProfilePicClickListener = View.OnClickListener {
- val hasStories = viewModel.userStories.value?.data?.isNotEmpty() ?: false
+ val hasStories = viewModel.userStories.value?.data != null
if (!hasStories) {
showProfilePicDialog()
return@OnClickListener
@@ -309,15 +309,7 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
viewModel = ViewModelProvider(
this,
ProfileFragmentViewModelFactory(
- csrfToken,
- deviceUuid,
- UserRepository.getInstance(),
- FriendshipRepository.getInstance(),
- StoriesRepository.getInstance(),
- MediaRepository.getInstance(),
- GraphQLRepository.getInstance(),
FavoriteRepository.getInstance(requireContext()),
- DirectMessagesRepository.getInstance(),
if (isLoggedIn) DirectMessagesManager else null,
this,
arguments
@@ -518,7 +510,7 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
highlightsAdapter?.submitList(it.data)
}
viewModel.userStories.observe(viewLifecycleOwner) {
- binding.header.mainProfileImage.setStoriesBorder(if (it.data.isNullOrEmpty()) 0 else 1)
+ binding.header.mainProfileImage.setStoriesBorder(if (it.data == null) 0 else 1)
}
viewModel.eventLiveData.observe(viewLifecycleOwner) {
val event = it?.getContentIfNotHandled() ?: return@observe
@@ -855,7 +847,7 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
private fun setupHighlights() {
val context = context ?: return
highlightsAdapter = HighlightsAdapter { model, position ->
- val options = StoryViewerOptions.forHighlight(model.title).apply { currentFeedStoryIndex = position }
+ val options = StoryViewerOptions.forHighlight(model.user!!.pk, "").apply { currentFeedStoryIndex = position }
val action = ProfileFragmentDirections.actionToStory(options)
NavHostFragment.findNavController(this).navigate(action)
}
@@ -942,7 +934,7 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
val action = ProfileFragmentDirections.actionToStory(
StoryViewerOptions.forUser(
viewModel.profile.value?.data?.pk ?: return,
- viewModel.profile.value?.data?.fullName ?: return,
+ viewModel.profile.value?.data?.username ?: return,
)
)
findNavController().navigate(action)
diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/PostPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/PostPreferencesFragment.java
index b1db2e40..4c91407f 100644
--- a/app/src/main/java/awais/instagrabber/fragments/settings/PostPreferencesFragment.java
+++ b/app/src/main/java/awais/instagrabber/fragments/settings/PostPreferencesFragment.java
@@ -18,7 +18,6 @@ public class PostPreferencesFragment extends BasePreferencesFragment {
// generalCategory.addPreference(getAutoPlayVideosPreference(context));
screen.addPreference(getBackgroundPlayPreference(context));
screen.addPreference(getAlwaysMuteVideosPreference(context));
- screen.addPreference(getShowCaptionPreference(context));
screen.addPreference(getToggleKeywordFilterPreference(context));
screen.addPreference(getEditKeywordFilterPreference(context));
}
@@ -48,15 +47,6 @@ public class PostPreferencesFragment extends BasePreferencesFragment {
return preference;
}
- private Preference getShowCaptionPreference(@NonNull final Context context) {
- final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
- preference.setKey(PreferenceKeys.SHOW_CAPTIONS);
- preference.setDefaultValue(true);
- preference.setTitle(R.string.post_viewer_show_captions);
- preference.setIconSpaceReserved(false);
- return preference;
- }
-
private Preference getToggleKeywordFilterPreference(@NonNull final Context context) {
final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
preference.setKey(PreferenceKeys.TOGGLE_KEYWORD_FILTER);
diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.kt b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.kt
index 161a4a9b..450b31f5 100644
--- a/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.kt
+++ b/app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.kt
@@ -12,6 +12,7 @@ object PreferenceKeys {
const val PREF_SEARCH_FOCUS_KEYBOARD = "search_focus_keyboard"
const val PREF_AUTO_BACKUP_ENABLED = "auto_backup_enabled"
const val PREF_DISABLE_SCREEN_TRANSITIONS = "disable_screen_transitions"
+ const val PREF_STORY_SHOW_LIST = "story_show_list"
// string prefs
const val FOLDER_PATH = "custom_path"
@@ -33,7 +34,7 @@ object PreferenceKeys {
const val PLAY_IN_BACKGROUND = "play_in_background"
const val AUTOPLAY_VIDEOS_STORIES = "autoplay_videos"
const val MUTED_VIDEOS = "muted_videos"
- const val SHOW_CAPTIONS = "show_captions"
+// const val SHOW_CAPTIONS = "show_captions"
const val CUSTOM_DATE_TIME_FORMAT_ENABLED = "data_time_custom_enabled"
const val SWAP_DATE_TIME_FORMAT_ENABLED = "swap_date_time_enabled"
const val MARK_AS_SEEN = "mark_as_seen"
diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java
index 2983d216..62b7c0ae 100644
--- a/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java
+++ b/app/src/main/java/awais/instagrabber/fragments/settings/StoriesPreferencesFragment.java
@@ -19,6 +19,7 @@ public class StoriesPreferencesFragment extends BasePreferencesFragment {
screen.addPreference(getHideMutedReelsPreference(context));
screen.addPreference(getMarkStoriesSeenPreference(context));
screen.addPreference(getAutoPlayPreference(context));
+ screen.addPreference(getStoryListPreference(context));
}
private Preference getStorySortPreference(@NonNull final Context context) {
@@ -62,4 +63,13 @@ public class StoriesPreferencesFragment extends BasePreferencesFragment {
preference.setIconSpaceReserved(false);
return preference;
}
+
+ private Preference getStoryListPreference(@NonNull final Context context) {
+ final SwitchPreferenceCompat preference = new SwitchPreferenceCompat(context);
+ preference.setKey(PreferenceKeys.PREF_STORY_SHOW_LIST);
+ preference.setTitle(R.string.story_list_setting);
+ preference.setSummary(R.string.story_list_setting_summary);
+ preference.setIconSpaceReserved(false);
+ return preference;
+ }
}
diff --git a/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt b/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt
index 34df42d4..69d2afa9 100644
--- a/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt
+++ b/app/src/main/java/awais/instagrabber/managers/DirectMessagesManager.kt
@@ -102,8 +102,8 @@ object DirectMessagesManager {
data.postValue(loading(null))
scope.launch(Dispatchers.IO) {
try {
- if (itemType == BroadcastItemType.MEDIA_SHARE)
- directMessagesRepository.broadcastMediaShare(
+ when (itemType) {
+ BroadcastItemType.MEDIA_SHARE -> directMessagesRepository.broadcastMediaShare(
csrfToken,
viewerId,
deviceUuid,
@@ -112,8 +112,7 @@ object DirectMessagesManager {
mediaId,
secondId
)
- if (itemType == BroadcastItemType.PROFILE)
- directMessagesRepository.broadcastProfile(
+ BroadcastItemType.PROFILE -> directMessagesRepository.broadcastProfile(
csrfToken,
viewerId,
deviceUuid,
@@ -121,6 +120,16 @@ object DirectMessagesManager {
ThreadIdsOrUserIds(threadIds, userIds),
mediaId
)
+ BroadcastItemType.STORY -> directMessagesRepository.broadcastStory(
+ csrfToken,
+ viewerId,
+ deviceUuid,
+ UUID.randomUUID().toString(),
+ ThreadIdsOrUserIds(threadIds, userIds),
+ mediaId,
+ secondId!!
+ )
+ }
data.postValue(success(Any()))
callback?.invoke()
} catch (e: Exception) {
@@ -132,6 +141,42 @@ object DirectMessagesManager {
return data
}
+ fun replyToStory(
+ recipientId: Long?,
+ reelId: String?,
+ mediaId: String?,
+ text: String,
+ scope: CoroutineScope
+ ): LiveData> {
+ Log.d("austin_debug", "replying")
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ if (recipientId == null || reelId == null || mediaId == null) {
+ data.postValue(error("arguments are null", null))
+ return data
+ }
+ scope.launch(Dispatchers.IO) {
+ try {
+ directMessagesRepository.broadcastStoryReply(
+ csrfToken,
+ viewerId,
+ deviceUuid,
+ ThreadIdsOrUserIds.Companion.ofOneUser(recipientId.toString(10)),
+ text,
+ mediaId,
+ reelId
+ )
+ inboxManager.refresh(scope)
+ data.postValue(success(null))
+ }
+ catch (e: Exception) {
+ Log.e(TAG, "story reply: ", e)
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
init {
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
viewerId = getUserIdFromCookie(cookie)
diff --git a/app/src/main/java/awais/instagrabber/models/enums/StoryPaginationType.kt b/app/src/main/java/awais/instagrabber/models/enums/StoryPaginationType.kt
new file mode 100644
index 00000000..5bdb4f8f
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/models/enums/StoryPaginationType.kt
@@ -0,0 +1,7 @@
+package awais.instagrabber.models.enums
+
+import java.io.Serializable
+
+enum class StoryPaginationType : Serializable {
+ FORWARD, BACKWARD, DO_NOTHING, ERROR
+}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt b/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt
index e964f54b..c8920d74 100644
--- a/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/StoriesService.kt
@@ -29,12 +29,12 @@ interface StoriesService {
suspend fun getStories(@Path("type") type: String, @Path("id") id: String): ReelsResponse
@GET("/api/v1/feed/user/{id}/story/")
- suspend fun getUserStories(@Path("id") id: String): ReelsResponse
+ suspend fun getUserStories(@Path("id") id: Long): ReelsResponse
@FormUrlEncoded
@POST("/api/v1/media/{storyId}/{stickerId}/{action}/")
suspend fun respondToSticker(
- @Path("storyId") storyId: String,
+ @Path("storyId") storyId: Long,
@Path("stickerId") stickerId: Long,
@Path("action") action: String, // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer
@FieldMap form: Map,
diff --git a/app/src/main/java/awais/instagrabber/repositories/requests/StoryViewerOptions.java b/app/src/main/java/awais/instagrabber/repositories/requests/StoryViewerOptions.java
index 8202ec7d..7a82a298 100644
--- a/app/src/main/java/awais/instagrabber/repositories/requests/StoryViewerOptions.java
+++ b/app/src/main/java/awais/instagrabber/repositories/requests/StoryViewerOptions.java
@@ -45,8 +45,8 @@ public class StoryViewerOptions implements Serializable {
return new StoryViewerOptions(id, name, Type.USER);
}
- public static StoryViewerOptions forHighlight(final String highlight) {
- return new StoryViewerOptions(highlight, Type.HIGHLIGHT);
+ public static StoryViewerOptions forHighlight(final long id, final String highlight) {
+ return new StoryViewerOptions(id, highlight, Type.HIGHLIGHT);
}
public static StoryViewerOptions forStory(final long mediaId, final String username) {
diff --git a/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.kt b/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.kt
index 48dec941..5de0991c 100644
--- a/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/requests/directmessages/StoryReplyBroadcastOptions.kt
@@ -7,7 +7,7 @@ class StoryReplyBroadcastOptions(
threadIdsOrUserIds: ThreadIdsOrUserIds,
val text: String,
val mediaId: String,
- val reelId: String // or user id, usually same
+ val reelId: String
) : BroadcastOptions(clientContext, threadIdsOrUserIds, BroadcastItemType.REELSHARE) {
override val formMap: Map
get() = mapOf(
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuestionSticker.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuestionSticker.kt
index 7dfec43c..87801293 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuestionSticker.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuestionSticker.kt
@@ -6,7 +6,7 @@ import awais.instagrabber.repositories.responses.Location
import awais.instagrabber.repositories.responses.User
data class QuestionSticker(
- val questionType: String?,
+ val questionType: String,
val questionId: Long,
val question: String
) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuizSticker.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuizSticker.kt
index 45f237f2..4158490f 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuizSticker.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/QuizSticker.kt
@@ -6,8 +6,8 @@ import awais.instagrabber.repositories.responses.Location
import awais.instagrabber.repositories.responses.User
data class QuizSticker(
- val quizId: Long?,
- val question: String?,
+ val quizId: Long,
+ val question: String,
val tallies: List,
var viewerAnswer: Int?,
val correctAnswer: Int
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/SliderSticker.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/SliderSticker.kt
index 45356d85..ca6a536b 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/SliderSticker.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/SliderSticker.kt
@@ -6,11 +6,11 @@ import awais.instagrabber.repositories.responses.Location
import awais.instagrabber.repositories.responses.User
data class SliderSticker(
- val sliderId: Long?,
- val question: String?,
+ val sliderId: Long,
+ val question: String,
val emoji: String?,
val viewerCanVote: Boolean?,
- var viewerVote: Double?,
+ val viewerVote: Double?,
val sliderVoteAverage: Double?,
val sliderVoteCount: Int?,
) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryAppAttribution.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryAppAttribution.kt
index 6ae27957..bf8e524d 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryAppAttribution.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryAppAttribution.kt
@@ -1,9 +1,18 @@
package awais.instagrabber.repositories.responses.stories
+import android.net.Uri
import java.io.Serializable
// https://github.com/austinhuang0131/barinsta/issues/1151
data class StoryAppAttribution(
- val name: String?, // use name instead of app_action_text for button label
+ val name: String?,
+ val appActionText: String?,
val contentUrl: String?
-) : Serializable
\ No newline at end of file
+) : Serializable {
+ val url: String?
+ get() {
+ val uri = Uri.parse(contentUrl)
+ return if (uri.getHost().equals("open.spotify.com")) contentUrl?.split("?")?.get(0)
+ else contentUrl
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt
index f9559fd0..399e11ca 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/StoryMedia.kt
@@ -10,8 +10,8 @@ import java.io.Serializable
data class StoryMedia(
// inherited from Media
- val pk: String? = null,
- val id: String? = null,
+ val pk: Long = -1,
+ val id: String = "",
val takenAt: Long = -1,
val user: User? = null,
val canReshare: Boolean = false,
diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/stories/Tally.kt b/app/src/main/java/awais/instagrabber/repositories/responses/stories/Tally.kt
index 87c8c960..d71f1668 100644
--- a/app/src/main/java/awais/instagrabber/repositories/responses/stories/Tally.kt
+++ b/app/src/main/java/awais/instagrabber/repositories/responses/stories/Tally.kt
@@ -6,6 +6,6 @@ import awais.instagrabber.repositories.responses.Location
import awais.instagrabber.repositories.responses.User
data class Tally(
- val text: String?,
- val count: Int?
+ val text: String,
+ val count: Int
) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt
index 14410239..d3021e32 100644
--- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt
+++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.kt
@@ -209,9 +209,7 @@ object DownloadUtils {
val extension = getFileExtensionFromUrl(displayUrl)
val usernamePrepend = if (isEmpty(username)) "" else username + "_"
val fileName = usernamePrepend + postId + sliderPostfix + extension
- val mimeType = Utils.mimeTypeMap.getMimeTypeFromExtension(
- if (extension.startsWith(".")) extension.substring(1) else extension
- )
+ val mimeType = Utils.mimeTypeMap.getMimeTypeFromExtension(extension)
return Pair(fileName, mimeType!!)
}
@@ -269,7 +267,7 @@ object DownloadUtils {
) {
val dotPos = filename.lastIndexOf('.')
if (0 <= dotPos) {
- return filename.substring(dotPos)
+ return filename.substring(dotPos + 1)
}
}
}
diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.kt b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.kt
index 14c8d1f5..e59e21ca 100755
--- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.kt
+++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.kt
@@ -121,7 +121,7 @@ class SettingsHelper(context: Context) {
PreferenceKeys.DOWNLOAD_PREPEND_USER_NAME,
PreferenceKeys.AUTOPLAY_VIDEOS_STORIES,
PreferenceKeys.MUTED_VIDEOS,
- PreferenceKeys.SHOW_CAPTIONS,
+// PreferenceKeys.SHOW_CAPTIONS,
PreferenceKeys.CUSTOM_DATE_TIME_FORMAT_ENABLED,
PreferenceKeys.MARK_AS_SEEN,
PreferenceKeys.DM_MARK_AS_SEEN,
@@ -137,6 +137,7 @@ class SettingsHelper(context: Context) {
PreferenceKeys.PLAY_IN_BACKGROUND,
PreferenceKeys.PREF_SHOWN_COUNT_TOOLTIP,
PreferenceKeys.PREF_SEARCH_FOCUS_KEYBOARD,
+ PreferenceKeys.PREF_STORY_SHOW_LIST,
PreferenceKeys.PREF_AUTO_BACKUP_ENABLED
)
annotation class BooleanSettings
diff --git a/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java
deleted file mode 100644
index ccc8b843..00000000
--- a/app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package awais.instagrabber.viewmodels;
-
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-import java.util.List;
-
-import awais.instagrabber.repositories.responses.stories.Story;
-
-public class HighlightsViewModel extends ViewModel {
- private MutableLiveData> list;
-
- public MutableLiveData> getList() {
- if (list == null) {
- list = new MutableLiveData<>();
- }
- return list;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt b/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt
index d133d918..33550f70 100644
--- a/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt
+++ b/app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt
@@ -16,10 +16,12 @@ import awais.instagrabber.repositories.responses.User
import awais.instagrabber.repositories.responses.UserProfileContextLink
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
import awais.instagrabber.repositories.responses.stories.Story
-import awais.instagrabber.repositories.responses.stories.StoryMedia
+import awais.instagrabber.utils.Constants
import awais.instagrabber.utils.ControlledRunner
import awais.instagrabber.utils.Event
+import awais.instagrabber.utils.getCsrfTokenFromCookie
import awais.instagrabber.utils.SingleRunner
+import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.utils.extensions.isReallyPrivate
import awais.instagrabber.viewmodels.ProfileFragmentViewModel.ProfileAction.*
@@ -32,18 +34,20 @@ import java.time.LocalDateTime
class ProfileFragmentViewModel(
private val state: SavedStateHandle,
- private val csrfToken: String?,
- private val deviceUuid: String?,
- private val userRepository: UserRepository,
- private val friendshipRepository: FriendshipRepository,
- private val storiesRepository: StoriesRepository,
- private val mediaRepository: MediaRepository,
- private val graphQLRepository: GraphQLRepository,
- private val favoriteRepository: FavoriteRepository,
- private val directMessagesRepository: DirectMessagesRepository,
+ private val favoriteRepository: FavoriteRepository?,
private val messageManager: DirectMessagesManager?,
ioDispatcher: CoroutineDispatcher,
) : ViewModel() {
+ private val cookie: String = Utils.settingsHelper.getString(Constants.COOKIE)
+ private val csrfToken: String? = getCsrfTokenFromCookie(cookie)
+ private val deviceUuid: String = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
+ private val userRepository: UserRepository by lazy { UserRepository.getInstance() }
+ private val friendshipRepository: FriendshipRepository by lazy { FriendshipRepository.getInstance() }
+ private val storiesRepository: StoriesRepository by lazy { StoriesRepository.getInstance() }
+ private val mediaRepository: MediaRepository by lazy { MediaRepository.getInstance() }
+ private val graphQLRepository: GraphQLRepository by lazy { GraphQLRepository.getInstance() }
+ private val directMessagesRepository: DirectMessagesRepository by lazy { DirectMessagesRepository.getInstance() }
+
private val _currentUser = MutableLiveData>(Resource.loading(null))
private val _isFavorite = MutableLiveData(false)
private val profileAction = MutableLiveData(INIT)
@@ -157,9 +161,9 @@ class ProfileFragmentViewModel(
}
}
- private val storyFetchControlledRunner = ControlledRunner?>()
- val userStories: LiveData?>> = currentUserProfileActionLiveData.switchMap { currentUserAndProfilePair ->
- liveData?>>(context = viewModelScope.coroutineContext + ioDispatcher) {
+ private val storyFetchControlledRunner = ControlledRunner()
+ val userStories: LiveData> = currentUserProfileActionLiveData.switchMap { currentUserAndProfilePair ->
+ liveData>(context = viewModelScope.coroutineContext + ioDispatcher) {
val (currentUserResource, profileResource, action) = currentUserAndProfilePair
if (action != INIT && action != REFRESH) {
return@liveData
@@ -235,7 +239,7 @@ class ProfileFragmentViewModel(
return graphQLRepository.fetchUser(stateUsername)
}
- private suspend fun fetchUserStory(fetchedUser: User): List = storiesRepository.getStories(
+ private suspend fun fetchUserStory(fetchedUser: User): Story? = storiesRepository.getStories(
StoryViewerOptions.forUser(fetchedUser.pk, fetchedUser.fullName)
)
@@ -243,7 +247,7 @@ class ProfileFragmentViewModel(
private suspend fun checkAndUpdateFavorite(fetchedUser: User) {
try {
- val favorite = favoriteRepository.getFavorite(fetchedUser.username, FavoriteType.USER)
+ val favorite = favoriteRepository!!.getFavorite(fetchedUser.username, FavoriteType.USER)
if (favorite == null) {
_isFavorite.postValue(false)
return
@@ -291,7 +295,7 @@ class ProfileFragmentViewModel(
viewModelScope.launch(Dispatchers.IO) {
toggleFavoriteControlledRunner.afterPrevious {
try {
- val favorite = favoriteRepository.getFavorite(username, FavoriteType.USER)
+ val favorite = favoriteRepository!!.getFavorite(username, FavoriteType.USER)
if (favorite == null) {
// insert
favoriteRepository.insertOrUpdateFavorite(
@@ -326,7 +330,7 @@ class ProfileFragmentViewModel(
val currentUserId = currentUser.value?.data?.pk ?: return@afterPrevious
val targetUserId = profile.value?.data?.pk ?: return@afterPrevious
val csrfToken = csrfToken ?: return@afterPrevious
- val deviceUuid = deviceUuid ?: return@afterPrevious
+ val deviceUuid = deviceUuid
if (following) {
if (!confirmed) {
_eventLiveData.postValue(Event(ShowConfirmUnfollowDialog))
@@ -365,7 +369,7 @@ class ProfileFragmentViewModel(
val currentUserId = currentUser.value?.data?.pk ?: return@afterPrevious
val targetUserId = profile.value?.data?.pk ?: return@afterPrevious
val csrfToken = csrfToken ?: return@afterPrevious
- val deviceUuid = deviceUuid ?: return@afterPrevious
+ val deviceUuid = deviceUuid
val username = profile.value?.data?.username ?: return@afterPrevious
val thread = directMessagesRepository.createThread(
csrfToken,
@@ -399,7 +403,7 @@ class ProfileFragmentViewModel(
val profile = profile.value?.data ?: return@afterPrevious
friendshipRepository.toggleRestrict(
csrfToken ?: return@afterPrevious,
- deviceUuid ?: return@afterPrevious,
+ deviceUuid,
profile.pk,
!(profile.friendshipStatus?.isRestricted ?: false),
)
@@ -421,7 +425,7 @@ class ProfileFragmentViewModel(
friendshipRepository.changeBlock(
csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious,
- deviceUuid ?: return@afterPrevious,
+ deviceUuid,
profile.friendshipStatus?.blocking ?: return@afterPrevious,
profile.pk
)
@@ -443,7 +447,7 @@ class ProfileFragmentViewModel(
friendshipRepository.changeMute(
csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious,
- deviceUuid ?: return@afterPrevious,
+ deviceUuid,
profile.friendshipStatus?.isMutingReel ?: return@afterPrevious,
profile.pk,
true
@@ -466,7 +470,7 @@ class ProfileFragmentViewModel(
friendshipRepository.changeMute(
csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious,
- deviceUuid ?: return@afterPrevious,
+ deviceUuid,
profile.friendshipStatus?.muting ?: return@afterPrevious,
profile.pk,
false
@@ -488,7 +492,7 @@ class ProfileFragmentViewModel(
friendshipRepository.removeFollower(
csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious,
- deviceUuid ?: return@afterPrevious,
+ deviceUuid,
profile.value?.data?.pk ?: return@afterPrevious
)
profileAction.postValue(REFRESH_FRIENDSHIP)
@@ -597,15 +601,7 @@ class ProfileFragmentViewModel(
@Suppress("UNCHECKED_CAST")
class ProfileFragmentViewModelFactory(
- private val csrfToken: String?,
- private val deviceUuid: String?,
- private val userRepository: UserRepository,
- private val friendshipRepository: FriendshipRepository,
- private val storiesRepository: StoriesRepository,
- private val mediaRepository: MediaRepository,
- private val graphQLRepository: GraphQLRepository,
- private val favoriteRepository: FavoriteRepository,
- private val directMessagesRepository: DirectMessagesRepository,
+ private val favoriteRepository: FavoriteRepository?,
private val messageManager: DirectMessagesManager?,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null,
@@ -617,15 +613,7 @@ class ProfileFragmentViewModelFactory(
): T {
return ProfileFragmentViewModel(
handle,
- csrfToken,
- deviceUuid,
- userRepository,
- friendshipRepository,
- storiesRepository,
- mediaRepository,
- graphQLRepository,
favoriteRepository,
- directMessagesRepository,
messageManager,
Dispatchers.IO,
) as T
diff --git a/app/src/main/java/awais/instagrabber/viewmodels/StoriesViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/StoriesViewModel.java
deleted file mode 100644
index 0f512403..00000000
--- a/app/src/main/java/awais/instagrabber/viewmodels/StoriesViewModel.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package awais.instagrabber.viewmodels;
-
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-import java.util.List;
-
-import awais.instagrabber.repositories.responses.stories.StoryMedia;
-
-public class StoriesViewModel extends ViewModel {
- private MutableLiveData> list;
-
- public MutableLiveData> getList() {
- if (list == null) {
- list = new MutableLiveData<>();
- }
- return list;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/viewmodels/StoryFragmentViewModel.kt b/app/src/main/java/awais/instagrabber/viewmodels/StoryFragmentViewModel.kt
new file mode 100644
index 00000000..d463c251
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/viewmodels/StoryFragmentViewModel.kt
@@ -0,0 +1,475 @@
+package awais.instagrabber.viewmodels
+
+import android.net.Uri
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import awais.instagrabber.R
+import awais.instagrabber.managers.DirectMessagesManager
+import awais.instagrabber.models.enums.FavoriteType
+import awais.instagrabber.models.enums.MediaItemType
+import awais.instagrabber.models.enums.StoryPaginationType
+import awais.instagrabber.models.Resource
+import awais.instagrabber.models.Resource.Companion.error
+import awais.instagrabber.models.Resource.Companion.loading
+import awais.instagrabber.models.Resource.Companion.success
+import awais.instagrabber.models.enums.BroadcastItemType
+import awais.instagrabber.repositories.requests.StoryViewerOptions
+import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
+import awais.instagrabber.repositories.responses.stories.*
+import awais.instagrabber.repositories.responses.Media
+import awais.instagrabber.utils.*
+import awais.instagrabber.webservices.MediaRepository
+import awais.instagrabber.webservices.StoriesRepository
+import com.google.common.collect.ImmutableList
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class StoryFragmentViewModel : ViewModel() {
+ // large data
+ private val currentStory = MutableLiveData()
+ private val currentMedia = MutableLiveData()
+
+ // small data
+ private val storyTitle = MutableLiveData()
+ private val date = MutableLiveData()
+ private val type = MutableLiveData()
+ private val poll = MutableLiveData()
+ private val quiz = MutableLiveData()
+ private val question = MutableLiveData()
+ private val slider = MutableLiveData()
+ private val swipeUp = MutableLiveData()
+ private val linkedPost = MutableLiveData()
+ private val appAttribution = MutableLiveData()
+ private val reelMentions = MutableLiveData>>()
+
+ // process
+ private val currentIndex = MutableLiveData()
+ private val pagination = MutableLiveData(StoryPaginationType.DO_NOTHING)
+ private val options = MutableLiveData>, String?, String?>>()
+ private val seen = MutableLiveData>()
+
+ // utils
+ private var messageManager: DirectMessagesManager? = null
+ private val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
+ private val deviceId = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
+ private val csrfToken = getCsrfTokenFromCookie(cookie)
+ private val userId = getUserIdFromCookie(cookie)
+ private val storiesRepository: StoriesRepository by lazy { StoriesRepository.getInstance() }
+ private val mediaRepository: MediaRepository by lazy { MediaRepository.getInstance() }
+
+ // for highlights ONLY
+ private val highlights = MutableLiveData?>()
+
+ /* set functions */
+
+ fun setStory(story: Story) {
+ if (story.items == null || story.items.size == 0) {
+ pagination.postValue(StoryPaginationType.ERROR)
+ return
+ }
+ currentStory.postValue(story)
+ storyTitle.postValue(story.title ?: story.user?.username)
+ if (story.broadcast != null) {
+ date.postValue(story.dateTime)
+ type.postValue(MediaItemType.MEDIA_TYPE_LIVE)
+ pagination.postValue(StoryPaginationType.DO_NOTHING)
+ }
+ }
+
+ fun setMedia(index: Int) {
+ if (currentStory.value?.items == null) return
+ if (index < 0 || index >= currentStory.value!!.items!!.size) {
+ pagination.postValue(if (index < 0) StoryPaginationType.BACKWARD else StoryPaginationType.FORWARD)
+ return
+ }
+ currentIndex.postValue(index)
+ val story: Story? = currentStory.value
+ val media = story!!.items!!.get(index)
+ currentMedia.postValue(media)
+ date.postValue(media.date)
+ type.postValue(media.type)
+ initStickers(media)
+ }
+
+ fun setSingleMedia(media: StoryMedia) {
+ currentStory.postValue(null)
+ currentIndex.postValue(0)
+ currentMedia.postValue(media)
+ date.postValue(media.date)
+ type.postValue(media.type)
+ }
+
+ private fun initStickers(media: StoryMedia) {
+ val builder = ImmutableList.builder>()
+ var linkedText: String? = null
+ var appText: String? = null
+ if (setMentions(media)) builder.add(Pair(R.id.mentions, R.string.story_mentions))
+ if (setQuiz(media)) builder.add(Pair(R.id.quiz, R.string.story_quiz))
+ if (setQuestion(media)) builder.add(Pair(R.id.question, R.string.story_question))
+ if (setPoll(media)) builder.add(Pair(R.id.poll, R.string.story_poll))
+ if (setSlider(media)) builder.add(Pair(R.id.slider, R.string.story_slider))
+ if (setLinkedPost(media)) builder.add(Pair(R.id.viewStoryPost, R.string.view_post))
+ if (setStoryCta(media)) {
+ linkedText = media.linkText
+ builder.add(Pair(R.id.swipeUp, 0))
+ }
+ if (setStoryAppAttribution(media)) {
+ appText = media.storyAppAttribution!!.appActionText
+ builder.add(Pair(R.id.spotify, 0))
+ }
+ options.postValue(Triple(builder.build(), linkedText, appText))
+ }
+
+ private fun setMentions(media: StoryMedia): Boolean {
+ val mentions: MutableList> = mutableListOf()
+ if (media.reelMentions != null)
+ mentions.addAll(media.reelMentions.map{
+ Triple("@" + it.user?.username, it.user?.username, FavoriteType.USER)
+ })
+ if (media.storyHashtags != null)
+ mentions.addAll(media.storyHashtags.map{
+ Triple("#" + it.hashtag?.name, it.hashtag?.name, FavoriteType.HASHTAG)
+ })
+ if (media.storyLocations != null)
+ mentions.addAll(media.storyLocations.map{
+ Triple(it.location?.name ?: "", it.location?.pk?.toString(10), FavoriteType.LOCATION)
+ })
+ reelMentions.postValue(mentions.filterNot { it.second.isNullOrEmpty() } .distinct())
+ return !mentions.isEmpty()
+ }
+
+ private fun setPoll(media: StoryMedia): Boolean {
+ poll.postValue(media.storyPolls?.get(0)?.pollSticker ?: return false)
+ return true
+ }
+
+ private fun setQuiz(media: StoryMedia): Boolean {
+ quiz.postValue(media.storyQuizs?.get(0)?.quizSticker ?: return false)
+ return true
+ }
+
+ private fun setQuestion(media: StoryMedia): Boolean {
+ val questionSticker = media.storyQuestions?.get(0)?.questionSticker ?: return false
+ if (questionSticker.questionType.equals("music")) return false
+ question.postValue(questionSticker)
+ return true
+ }
+
+ private fun setSlider(media: StoryMedia): Boolean {
+ slider.postValue(media.storySliders?.get(0)?.sliderSticker ?: return false)
+ return true
+ }
+
+ private fun setLinkedPost(media: StoryMedia): Boolean {
+ linkedPost.postValue(media.storyFeedMedia?.get(0)?.mediaId ?: return false)
+ return true
+ }
+
+ private fun setStoryCta(media: StoryMedia): Boolean {
+ val webUri = media.storyCta?.get(0)?.links?.get(0)?.webUri ?: return false
+ val parsedUri = Uri.parse(webUri)
+ val cleanUri = if (parsedUri.host.equals("l.instagram.com")) parsedUri.getQueryParameter("u")
+ else null
+ swipeUp.postValue(if (cleanUri != null && Uri.parse(cleanUri).scheme?.startsWith("http") == true) cleanUri
+ else webUri)
+ return true
+ }
+
+ private fun setStoryAppAttribution(media: StoryMedia): Boolean {
+ appAttribution.postValue(media.storyAppAttribution ?: return false)
+ return true
+ }
+
+ /* get functions */
+
+ fun getHighlights(): LiveData?> {
+ return highlights
+ }
+
+ fun getCurrentStory(): LiveData {
+ return currentStory
+ }
+
+ fun getCurrentIndex(): LiveData {
+ return currentIndex
+ }
+
+ fun getCurrentMedia(): LiveData {
+ return currentMedia
+ }
+
+ fun getPagination(): LiveData {
+ return pagination
+ }
+
+ fun getDate(): LiveData {
+ return date
+ }
+
+ fun getTitle(): LiveData {
+ return storyTitle
+ }
+
+ fun getType(): LiveData {
+ return type
+ }
+
+ fun getMedia(): LiveData {
+ return currentMedia
+ }
+
+ fun getMention(index: Int): Triple? {
+ return reelMentions.value?.get(index)
+ }
+
+ fun getMentionTexts(): Array {
+ return reelMentions.value!!.map { it.first } .toTypedArray()
+ }
+
+ fun getPoll(): LiveData {
+ return poll
+ }
+
+ fun getQuestion(): LiveData {
+ return question
+ }
+
+ fun getQuiz(): LiveData {
+ return quiz
+ }
+
+ fun getSlider(): LiveData {
+ return slider
+ }
+
+ fun getLinkedPost(): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ val postId = linkedPost.value
+ if (postId == null) data.postValue(error("No post ID supplied", null))
+ else viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val media = mediaRepository.fetch(postId.toLong())
+ data.postValue(success(media))
+ }
+ catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
+ fun getSwipeUp(): String? {
+ return swipeUp.value
+ }
+
+ fun getAppAttribution(): String? {
+ return appAttribution.value?.url
+ }
+
+ fun getOptions(): LiveData>, String?, String?>> {
+ return options
+ }
+
+ /* action functions */
+
+ fun answerPoll(w: Int): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val oldPoll: PollSticker = poll.value!!
+ val response = storiesRepository.respondToPoll(
+ csrfToken!!,
+ userId,
+ deviceId,
+ currentMedia.value!!.pk,
+ oldPoll.pollId,
+ w
+ )
+ if (!"ok".equals(response.status))
+ throw Exception("Instagram returned status \"" + response.status + "\"")
+ val tally = oldPoll.tallies.get(w)
+ val newTally = tally.copy(count = tally.count + 1)
+ val newTallies = oldPoll.tallies.toMutableList()
+ newTallies.set(w, newTally)
+ poll.postValue(oldPoll.copy(viewerVote = w, tallies = newTallies.toList()))
+ data.postValue(success(null))
+ }
+ catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
+ fun answerQuiz(w: Int): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val oldQuiz = quiz.value!!
+ val response = storiesRepository.respondToQuiz(
+ csrfToken!!,
+ userId,
+ deviceId,
+ currentMedia.value!!.pk,
+ oldQuiz.quizId,
+ w
+ )
+ if (!"ok".equals(response.status))
+ throw Exception("Instagram returned status \"" + response.status + "\"")
+ val tally = oldQuiz.tallies.get(w)
+ val newTally = tally.copy(count = tally.count + 1)
+ val newTallies = oldQuiz.tallies.toMutableList()
+ newTallies.set(w, newTally)
+ quiz.postValue(oldQuiz.copy(viewerAnswer = w, tallies = newTallies.toList()))
+ data.postValue(success(null))
+ }
+ catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
+ fun answerQuestion(a: String): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val response = storiesRepository.respondToQuestion(
+ csrfToken!!,
+ userId,
+ deviceId,
+ currentMedia.value!!.pk,
+ question.value!!.questionId,
+ a
+ )
+ if (!"ok".equals(response.status))
+ throw Exception("Instagram returned status \"" + response.status + "\"")
+ data.postValue(success(null))
+ }
+ catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
+ fun answerSlider(a: Double): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val oldSlider = slider.value!!
+ val response = storiesRepository.respondToSlider(
+ csrfToken!!,
+ userId,
+ deviceId,
+ currentMedia.value!!.pk,
+ oldSlider.sliderId,
+ a
+ )
+ if (!"ok".equals(response.status))
+ throw Exception("Instagram returned status \"" + response.status + "\"")
+ val newVoteCount = (oldSlider.sliderVoteCount ?: 0) + 1
+ val newAverage = if (oldSlider.sliderVoteAverage == null) a
+ else (oldSlider.sliderVoteAverage * oldSlider.sliderVoteCount!! + a) / newVoteCount
+ slider.postValue(oldSlider.copy(viewerCanVote = false,
+ sliderVoteCount = newVoteCount,
+ viewerVote = a,
+ sliderVoteAverage = newAverage))
+ data.postValue(success(null))
+ }
+ catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
+ fun reply(a: String): LiveData>? {
+ if (messageManager == null) {
+ messageManager = DirectMessagesManager
+ }
+ return messageManager?.replyToStory(
+ currentStory.value?.user?.pk,
+ currentStory.value?.id,
+ currentMedia.value?.id,
+ a,
+ viewModelScope
+ )
+ }
+
+ fun shareDm(result: RankedRecipient) {
+ if (messageManager == null) {
+ messageManager = DirectMessagesManager
+ }
+ val mediaId = currentMedia.value?.id ?: return
+ val reelId = currentStory.value?.id ?: return
+ messageManager?.sendMedia(result, mediaId, reelId, BroadcastItemType.STORY, viewModelScope)
+ }
+
+ fun shareDm(recipients: Set) {
+ if (messageManager == null) {
+ messageManager = DirectMessagesManager
+ }
+ val mediaId = currentMedia.value?.id ?: return
+ val reelId = currentStory.value?.id ?: return
+ messageManager?.sendMedia(recipients, mediaId, reelId, BroadcastItemType.STORY, viewModelScope)
+ }
+
+ fun paginate(backward: Boolean) {
+ var index = currentIndex.value!!
+ index = if (backward) index - 1 else index + 1
+ if (index < 0 || index >= currentStory.value!!.items!!.size) skip(backward)
+ setMedia(index)
+ }
+
+ fun skip(backward: Boolean) {
+ pagination.postValue(if (backward) StoryPaginationType.BACKWARD else StoryPaginationType.FORWARD)
+ }
+
+ fun fetchStory(fetchOptions: StoryViewerOptions?): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val story = storiesRepository.getStories(fetchOptions!!)
+ setStory(story!!)
+ data.postValue(success(null))
+ } catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+
+ fun fetchHighlights(id: Long) {
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val result = storiesRepository.fetchHighlights(id)
+ highlights.postValue(result)
+ } catch (e: Exception) {
+ }
+ }
+ }
+
+ fun fetchSingleMedia(mediaId: Long): LiveData> {
+ val data = MutableLiveData>()
+ data.postValue(loading(null))
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val storyMedia = storiesRepository.fetch(mediaId)
+ setSingleMedia(storyMedia!!)
+ data.postValue(success(null))
+ } catch (e: Exception) {
+ data.postValue(error(e.message, null))
+ }
+ }
+ return data
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt
index f21d35da..b3a12280 100644
--- a/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt
+++ b/app/src/main/java/awais/instagrabber/webservices/DirectMessagesRepository.kt
@@ -187,6 +187,17 @@ open class DirectMessagesRepository(private val service: DirectMessagesService)
): DirectThreadBroadcastResponse =
broadcast(csrfToken, userId, deviceUuid, ProfileBroadcastOptions(clientContext, threadIdsOrUserIds, profileId))
+ suspend fun broadcastStory(
+ csrfToken: String,
+ userId: Long,
+ deviceUuid: String,
+ clientContext: String,
+ threadIdsOrUserIds: ThreadIdsOrUserIds,
+ mediaId: String,
+ reelId: String,
+ ): DirectThreadBroadcastResponse =
+ broadcast(csrfToken, userId, deviceUuid, StoryBroadcastOptions(clientContext, threadIdsOrUserIds, mediaId, reelId))
+
private suspend fun broadcast(
csrfToken: String,
userId: Long,
diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt b/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt
index 62c27847..205983c9 100644
--- a/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt
+++ b/app/src/main/java/awais/instagrabber/webservices/StoriesRepository.kt
@@ -7,7 +7,6 @@ import awais.instagrabber.repositories.responses.stories.ArchiveResponse
import awais.instagrabber.repositories.responses.stories.Story
import awais.instagrabber.repositories.responses.stories.StoryMedia
import awais.instagrabber.repositories.responses.stories.StoryStickerResponse
-import awais.instagrabber.utils.TextUtils.isEmpty
import awais.instagrabber.utils.Utils
import awais.instagrabber.webservices.RetrofitFactory.retrofit
import java.util.UUID
@@ -60,35 +59,34 @@ open class StoriesRepository(private val service: StoriesService) {
"is_in_archive_home" to "true",
"include_cover" to "1",
)
- if (!isEmpty(maxId)) {
+ if (!maxId.isNullOrEmpty()) {
form["max_id"] = maxId // NOT TESTED
}
return service.fetchArchive(form)
}
- open suspend fun getStories(options: StoryViewerOptions): List {
+ open suspend fun getStories(options: StoryViewerOptions): Story? {
return when (options.type) {
StoryViewerOptions.Type.HIGHLIGHT,
StoryViewerOptions.Type.STORY_ARCHIVE
-> {
val response = service.getReelsMedia(options.name)
- val story: Story? = response.reels?.get(options.name)
- story?.items ?: emptyList()
+ response.reels?.get(options.name)
}
StoryViewerOptions.Type.USER -> {
- val response = service.getUserStories(options.id.toString())
- response.reel?.items ?: emptyList()
+ val response = service.getUserStories(options.id)
+ response.reel
}
// should not reach beyond this point
StoryViewerOptions.Type.LOCATION -> {
val response = service.getStories("locations", options.id.toString())
- response.story?.items ?: emptyList()
+ response.story
}
StoryViewerOptions.Type.HASHTAG -> {
val response = service.getStories("tags", options.name)
- response.story?.items ?: emptyList()
+ response.story
}
- else -> emptyList()
+ else -> null
}
}
@@ -96,7 +94,7 @@ open class StoriesRepository(private val service: StoriesService) {
csrfToken: String,
userId: Long,
deviceUuid: String,
- storyId: String,
+ storyId: Long,
stickerId: Long,
action: String,
arg1: String,
@@ -119,7 +117,7 @@ open class StoriesRepository(private val service: StoriesService) {
csrfToken: String,
userId: Long,
deviceUuid: String,
- storyId: String,
+ storyId: Long,
stickerId: Long,
answer: String,
): StoryStickerResponse = respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_question_response", "response", answer)
@@ -128,7 +126,7 @@ open class StoriesRepository(private val service: StoriesService) {
csrfToken: String,
userId: Long,
deviceUuid: String,
- storyId: String,
+ storyId: Long,
stickerId: Long,
answer: Int,
): StoryStickerResponse {
@@ -139,7 +137,7 @@ open class StoriesRepository(private val service: StoriesService) {
csrfToken: String,
userId: Long,
deviceUuid: String,
- storyId: String,
+ storyId: Long,
stickerId: Long,
answer: Int,
): StoryStickerResponse = respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_poll_vote", "vote", answer.toString())
@@ -148,7 +146,7 @@ open class StoriesRepository(private val service: StoriesService) {
csrfToken: String,
userId: Long,
deviceUuid: String,
- storyId: String,
+ storyId: Long,
stickerId: Long,
answer: Double,
): StoryStickerResponse = respondToSticker(csrfToken, userId, deviceUuid, storyId, stickerId, "story_slider_vote", "vote", answer.toString())
diff --git a/app/src/main/res/drawable/ic_story_sticker.xml b/app/src/main/res/drawable/ic_story_sticker.xml
new file mode 100644
index 00000000..a9079fe0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_story_sticker.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_story_viewer_list.xml b/app/src/main/res/drawable/ic_story_viewer_list.xml
new file mode 100644
index 00000000..c0450237
--- /dev/null
+++ b/app/src/main/res/drawable/ic_story_viewer_list.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/fragment_story_viewer.xml b/app/src/main/res/layout/fragment_story_viewer.xml
index cb6b66ed..bbce26f2 100644
--- a/app/src/main/res/layout/fragment_story_viewer.xml
+++ b/app/src/main/res/layout/fragment_story_viewer.xml
@@ -9,7 +9,7 @@
android:id="@+id/story_container"
android:layout_width="match_parent"
android:layout_height="0dp"
- app:layout_constraintBottom_toTopOf="@id/postActions"
+ app:layout_constraintBottom_toTopOf="@id/buttons_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -38,132 +38,150 @@
-
+ app:layout_constraintStart_toStartOf="parent" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
+ app:rippleColor="@color/grey_300" />
-
+
+
+
+
+
+
+
+
+ app:layout_constraintStart_toEndOf="@id/btnDownload"
+ app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
+ app:rippleColor="@color/grey_300" />
+ app:layout_constraintStart_toEndOf="@id/btnReply"
+ app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
+ app:rippleColor="@color/grey_300" />
\ No newline at end of file
diff --git a/app/src/main/res/menu/story_menu.xml b/app/src/main/res/menu/story_menu.xml
index 8169fd62..e7872ad5 100644
--- a/app/src/main/res/menu/story_menu.xml
+++ b/app/src/main/res/menu/story_menu.xml
@@ -2,21 +2,9 @@
\ No newline at end of file
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index cccace7d..6561c224 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -19,6 +19,7 @@
المفضلة
إكتشف
التعليقات
+ الردود
الأنشطة
التحقق من التحديثات عند بدء التشغيل
منع لقطات الشاشة & معاينة التطبيق
@@ -29,7 +30,7 @@
إخفاء القصص المكتومة من الخلاصة
تحديد DM كما هو بعد المشاهدة
الأعضاء الآخرون سيعلمون أنك شاهدتها
- Autoplay video stories
+ تشغيل تلقائي لقصص الفيديو
تمكين تنبيهات النشاط
تصنيف قصص التغذية
خطأ في تحميل الملف الشخصي! هل اسم المستخدم صحيح؟ إذا كان الأمر كذلك، قد تكون مقيدا.
@@ -65,7 +66,7 @@
- %s\nFollowers
- %s\nFollowers
- %s\nFollowing
+ %s\nمتابع
تشغيل مقاطع الفيديو تلقائياً
متابعة الفيديوهات في الخلفية
لا تقم بإيقاف الفيديوهات مؤقتاً عندما يكون التطبيق خارج نطاق التركيز
@@ -79,8 +80,7 @@
كن صبورا!
عرض المنشور
عرض المشاركة
- Spotify
- صوت
+ Poll
تم التصويت بنجاح!
لقد قمت بالتصويت بالفعل!
رد
@@ -101,8 +101,10 @@
شريط منزلق
لقد قمت بالرد مسبقا!
الإشارات
+ Question
هذا الحساب خاص
لن تتمكن من الوصول إلى المشاركات بعد إلغاء المتابعة! هل أنت متأكد؟
+ Are you sure?
يمكنك تسجيل الدخول عبر المزيد -> الحساب على الزاوية اليمنى السفلى أو يمكنك عرض الحسابات العامة بدون تسجيل الدخول!
هذا الحساب لا يتضمن مشاركات
لا توجد مثل هذه المشاركات!
@@ -117,50 +119,50 @@
حذف المجموعة
هل أنت متأكد من أنك تريد حذف هذه المجموعة؟
وستظل جميع الوسائط المحتوية في مجموعات أخرى.
- إضافة إلى المجموعة...
+ Add to collection…
إزالة من المجموعة
أعجبني
تم الحفظ
مشار إليها
الرسالة
- Bookmark
- Follow
- Unfollow
- Favorite
- Block
- Unblock
- Restrict
- Unrestrict
- Mute stories
- Mute posts
- Unmute stories
- Unmute posts
- Remove follower
- Copy bio
+ علامة مرجعية
+ تابع
+ إلغاء المتابعة
+ المفضلة
+ حظر
+ إلغاء الحظر
+ تقييد
+ إلغاء القيود
+ كتم القصص
+ كتم المشاركات
+ إلغاء كتم القصص
+ إلغاء كتم المنشورات
+ إزالة متابع
+ نسخ البيانات
Translate bio
Mutual
- Following
- Follower
- Map
- Accounts
- Settings
- Favorites
- Successfully imported!
- Failed to import!
- Successfully exported!
- Failed to export!
- Refresh
- Get cookies
- Use custom format
- Separator
- Time Format
- Date Format
- Preview
- Swap Time and Date positions
- Cannot delete currently in use account
- Are you sure you want to delete \'%s\'?
- Open profile
- View story
+ متابع
+ المتابعون
+ خريطه
+ الحسابات
+ الإعدادات
+ المفضلة
+ تمّ الإستيراد بنجاح!
+ فشل الاستيراد!
+ تمّ التصدير بنجاح!
+ فشل التصدير!
+ إعادة التحميل
+ الحصول على ملفات تعريف الارتباط
+ استخدام صيغة مخصصة
+ فاصل
+ تنسيق الوقت
+ تنسيق التاريخ
+ المعاينة
+ مبادلة اماكن الوقت والتاريخ
+ لا يمكن حذف الحساب المستخدم حاليا
+ هل أنت متأكد من أنك تريد حذف \"%s\"؟
+ فتح ملف شخصي
+ عرض القصة
View profile picture
Unsupported message type
Unsend message
@@ -196,9 +198,9 @@
Screenshotted
Cannot deliver
Unseen count response is null!
- Message...
+ Message…
Press and hold to record audio
- Updating...
+ Updating…
Leave chat
Leave this chat?
Kick
@@ -210,6 +212,7 @@
Downloads posts directly to the phone!
Fetching post(s)
Download completed
+ Preparing to download…
Downloading post…
Downloading media
Downloading profile picture
@@ -334,7 +337,7 @@
Comment
Layout
Feed stories
- Opening post...
+ Opening post…
Share
Layout style
Column count
@@ -522,7 +525,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
أعلى
@@ -532,7 +535,7 @@
انقر لعرض العدد الكلي للأعجابات
لم يتم العثور على صورة الملف الشخصي!
هل أنت متأكد من أنك تريد فتح هذا الرابط؟
- جار الإرسال...
+ Sending…
مشاركة عبر DM
مشاركة الرابط…
Slide to Cancel
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 9fb0f75c..8bf7a8fe 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -19,6 +19,7 @@
Preferits
Descobrir
Comentaris
+ Replies
Activitat
Cerca actualitzacions a l\'inici
Bloca les captures de pantalla & previsualització de l\'aplicació
@@ -67,8 +68,7 @@
Sigues pacient!
Mostrar l\'entrada
Mostrar l\'entrada
- Spotify
- Votar
+ Poll
Has votat amb èxit!
Ja has votat!
Contestar
@@ -85,8 +85,10 @@
Desplaçador
Ja has contestat!
Mencions
+ Question
Aquest compte és privat
Després de deixar de seguir, no podràs accedir a les publicacions. Estàs segur?
+ Are you sure?
Pots iniciar la sessió a través de Més ->; El teu compte és a l\'extrem inferior dret o pots veure comptes públics sense iniciar una sessió!
Aquest compte no té publicacions
No existeixen publicacions d\'aquest tipus!
@@ -101,7 +103,7 @@
Suprimeix la col·lecció
Estàs segur de voler suprimir aquesta col·lecció?
Tots els mitjans continguts romandran en altres col·leccions.
- Afegir a la coŀlecció...
+ Add to collection…
Eliminar de la coŀlecció
M\'agrada
Desat
@@ -180,9 +182,9 @@
Captura de pantalla feta
No es pot lliurar
La resposta de recompte no vista és nul·la!
- Missatge...
+ Message…
Premeu i mantingueu premut per enregistrar l\'àudio
- S\'està actualitzant...
+ Updating…
Deixar el xat
Vols sortir d\'aquest xat?
Expulsar
@@ -194,6 +196,7 @@
Descarregar publicacions directament al telèfon!
S\'estan recuperant les noves publicacions
S\'ha completat la descàrrega
+ Preparing to download…
Descarregant publicació…
Descarregant multimèdia
Descarregant la imatge de perfil
@@ -318,7 +321,7 @@
Comentar
Disposició
Fil d\'històries
- Obrint publicació...
+ Opening post…
Compartir
Estil de disposició
Nombre de columnes
@@ -486,7 +489,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Part superior
@@ -496,7 +499,7 @@
Feu clic per mostrar el recompte complet de m\'agrada
No s\'ha trobat cap imatge de perfil!
Esteu segur que voleu obrir aquest enllaç?
- Enviant...
+ Sending…
Comparteix via MD
Comparteix l\'enllaç...
Slide to Cancel
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index bc7b3db6..be7f21b0 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -19,6 +19,7 @@
Oblíbené
Objevit
Komentáře
+ Odpovědi
Aktivita
Zkontrolovat aktualizace při spuštění
Blokovat snímky obrazovky a náhled aplikace
@@ -73,8 +74,7 @@
Buďte trpěliví!
Zobrazit příspěvek
Zobrazit příspěvek
- Spotify
- Hlasovat
+ Hlasování
Hlasování úspěšné!
Již jste hlasovali!
Odpovědět
@@ -93,8 +93,10 @@
Posuvník
Už jste odpověděli!
Zmínky
+ Otázka
Tento účet je soukromý
Po zrušení sledování nebudete mít přístup k příspěvkům! Jste si jisti?
+ Určitě to chcete udělat?
Můžete se přihlásit přes Více -> Účet v pravém dolním rohu nebo můžete zobrazit veřejné účty bez přihlášení!
Tento účet nezveřejnil žádné příspěvky
Žádné takové příspěvky!
@@ -109,7 +111,7 @@
Odstranit sbírku
Opravdu chcete tuto sbírku odstranit?
Všechna uložená média zůstanou v jiných sbírkách.
- Přidat do sbírky...
+ Přidat do sbírky…
Odebrat ze sbírky
Líbí se
Uložené
@@ -188,9 +190,9 @@
Udělán snímek obrazovky
Nelze doručit
Unseen count response is null!
- Zpráva...
+ Zpráva…
Stiskněte a podržte pro nahrávání
- Aktualizace...
+ Aktualizace…
Opustit chat
Chcete opustit tento chat?
Vyhodit
@@ -202,6 +204,7 @@
Stahuje příspěvky přímo do telefonu!
Načítání příspěvků
Stahování bylo dokončeno
+ Připravuje se stahování…
Stahování příspěvku…
Stahování médií
Stahování profilového obrázku
@@ -294,8 +297,8 @@
Odebráno z Oblíbených!
Záloha a obnovení
Automatické zálohování
- Starting from Android 6, Android\'s Auto Backup feature will upload all app settings, account login data, and favorites onto your Google Drive, which can be restored by reinstalling the app after uninstallation.
- This preference has no effect if Google Play Services is not present, or if Auto Backup is disabled from your device settings. Disabling here does not erase existing backups.
+ Od Android 6 bude funkce zálohování Androidu automaticky nahrávat všechna nastavení aplikace, přihlašovací údaje a oblíbené na Disk Google. Tato záloha může být obnovena po opětovném nainstalování aplikace.
+ Toto nastavení nemá žádný účinek, pokud nejsou přítomny služby Google Play nebo pokud je automatické zálohování zakázáno v nastavení zařízení. Zakázání zde nevymaže existující zálohy.
Povolit automatické zálohování
Ruční zálohování
Zálohujte nastavení aplikace Barinsta, přihlašovací údaje a/nebo oblíbené položky do prostého textu nebo šifrovaného souboru pro pozdější obnovu.
@@ -326,7 +329,7 @@
Komentovat
Rozložení
Kanál příběhů
- Otevírání příspěvku...
+ Otevírání příspěvku…
Sdílet
Styl rozložení
Počet sloupců
@@ -504,17 +507,17 @@
Dříve vybraná složka už neexistuje:
Znovu vyberte adresář nebo vyberte nový adresář kliknutím na tlačítko níže.
Není vybrána žádná složka!
- Vyberte prosím adresář z vašeho úložiště, nikoli kategorii na postranním panelu.
+ Vyberte prosím adresář z vašeho úložiště, ne kategorii na postranním panelu.\n(%s)
Úspěch! Počkejte prosím. Spouštění aplikace…
Složka Barinsta
- Populární
+ Nejlepší
Nedávné
Vymazat
Nemáte žádnou aplikaci pro mapy!
Klepnutím zobrazíte přesný počet \"to se mi líbí\"
Nebyl nalezen žádný obrázek profilu!
Opravdu chcete otevřít tento odkaz?
- Odesílání...
+ Odesílání…
Sdílet do zprávy
Sdílet odkaz…
Posunutím zrušíte
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 93f78af7..4b602693 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -19,6 +19,7 @@
Favoriten
Entdecken
Kommentare
+ Antworten
Aktivität
Beim Start auf Updates prüfen
Bildschirmfotos & App-Vorschau verhindern
@@ -67,8 +68,7 @@
Sei etwas geduldig!
Beitrag anzeigen
Beitrag anzeigen
- Spotify
- Abstimmung
+ Poll
Abstimmung erfolgreich!
Du hast bereits abgestimmt!
Antworten
@@ -85,8 +85,10 @@
Schieberegler
Du hast bereits geantwortet!
Erwähnungen
+ Question
Dieser Account ist privat
Du wirst nicht mehr auf Beiträge zugreifen können, wenn du entfolgst! Bist du sicher?
+ Bist du sicher?
Du kannst dich unten rechts über Mehr -> anmelden, oder öffentliche Konten ohne Anmeldung ansehen!
Dieses Konto hat keine Beiträge
Keine derartigen Posts!
@@ -101,7 +103,7 @@
Sammlung löschen
Bist du sicher, dass du diese Sammlung löschen möchtest?
Alle enthaltenen Medien werden in anderen Sammlungen verbleiben.
- Zu Sammlung hinzufügen...
+ Add to collection…
Aus Sammlung entfernen
Gefällt mir
Gespeichert
@@ -180,9 +182,9 @@
Screenshot erstellt
Kann nicht zugestellt werden
Ungelesen-Zähler Antwort ist null!
- Nachricht...
+ Message…
Für Audioaufnahme drücken und halten
- Aktualisieren...
+ Updating…
Chat verlassen
Chat verlassen?
Entfernen
@@ -194,6 +196,7 @@
Lade Posts direkt auf das Handy herunter!
Beiträgen abrufen
Download abgeschlossen
+ Download wird vorbereitet…
Beitrag wird heruntergeladen…
Medien herunterladen
Profilbild wird heruntergeladen
@@ -318,7 +321,7 @@
Kommentar
Layout
Storyfeed
- Öffne Beitrag...
+ Opening post…
Teilen
Layoutstil
Spaltenanzahl
@@ -486,7 +489,7 @@
Der zuvor ausgewählte Ordner existiert nicht mehr:
Wähle das Verzeichnis erneut aus oder wähle ein neues Verzeichnis, indem du unten auf die Schaltfläche klickst.
Kein Ordner ausgewählt!
- Please choose a directory from your storage, not a category on the sidebar.
+ Bitte wähle ein Verzeichnis aus deinem Speicher, nicht eine Kategorie in der Seitenleiste.\n(%s)
Erfolg! Bitte warten. App wird gestartet…
Barinsta-Ordner
Anfang
@@ -496,7 +499,7 @@
Klicken, um die gesamte Anzahl der Likes anzuzeigen
Kein Profilbild gefunden!
Bist du sicher, dass du diesen Link öffnen möchtest?
- Wird gesendet...
+ Sending…
Über PN teilen
Link teilen…
Zum Abbrechen wischen
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 55810e73..e05c7782 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -1,7 +1,7 @@
Σχετικά με
- Απευθείας Μηνύματα
+ Μηνύματα
Ρυθμίσεις
Λήψη
Αναζήτηση ονόματος χρήστη…
@@ -19,6 +19,7 @@
Αγαπημένα
Ανακαλύψτε
Σχόλια
+ Απαντήσεις
Δραστηριότητα
Έλεγχος για ενημερώσεις κατά την εκκίνηση
Παρεμπόδιση στιγμιοτύπων οθόνης & προεπισκόπησης εφαρμογής
@@ -29,7 +30,7 @@
Απόκρυψη ιστοριών που βρίσκονται σε σίγαση από τη ροή
Επισήμανση μηνυμάτων ως αναγνωσμένων μετά την προβολή
Τα υπόλοιπα μέλη θα γνωρίζουν ότι προβλήθηκε
- Autoplay video stories
+ Αυτόματη αναπαραγωγή ιστοριών με βίντεο
Ενεργοποίηση ειδοποιήσεων δραστηριότητας
Ταξινόμηση ροής ιστορίων
Σφάλμα κατά τη φόρτωση προφίλ! Είναι το όνομα χρήστη έγκυρο; Αν ναι, μπορεί να είστε περιορισμένος.
@@ -67,8 +68,7 @@
Κάντε υπομονή!
Προβολή Δημοσίευσης
Προβολή Δημοσίευσης
- Spotify
- Ψηφίστε
+ Δημοσκόπηση
Η ψήφος ήταν επιτυχής!
Έχετε ήδη ψηφίσει!
Απάντηση
@@ -85,8 +85,10 @@
Slider
Έχετε ήδη απαντήσει!
Αναφορές
+ Ερώτηση
Ιδιωτικός λογαριασμός
Δε θα έχετε πρόσβαση στις δημοσιεύσεις μετά την άρση ακολούθησης! Είστε βέβαιος;
+ Είστε σίγουρος;
Μπορείτε να συνδεθείτε μέσω του Περισσότερα-> Λογαριασμός στην κάτω δεξιά γωνία ή μπορείτε να δείτε δημόσιους λογαριασμούς χωρίς σύνδεση!
Αυτός ο λογαριασμός δεν έχει δημοσιεύσεις
Δεν Υπάρχουν Τέτοιες Δημοσιεύσεις!
@@ -101,7 +103,7 @@
Διαγραφή συλλογής
Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτή τη συλλογή;
Όλα τα πολυμέσα που περιέχονται θα παραμείνουν σε άλλες συλλογές.
- Προσθήκη στη συλλογή...
+ Προσθήκη στη συλλογή…
Αφαίρεση από τη συλλογή
Μ\'αρέσουν
Αποθηκευμένα
@@ -180,9 +182,9 @@
Λήφθηκε στιγμιότυπο οθόνης
Αδυναμία παράδοσης
Η απόκριση καταμέτρησης μη προβληθέντων είναι άκυρη!
- Μήνυμα...
+ Μήνυμα…
Πατήστε παρατεταμένα για εγγραφή ήχου
- Ενημέρωση...
+ Ενημέρωση…
Αποχώρηση από τη συνομιλία
Αποχώρηση από αυτήν τη συνομιλία;
Διώξιμο
@@ -194,6 +196,7 @@
Γίνεται λήψη των δημοσιεύσεων απευθείας στο τηλέφωνο!
Ανάκτηση δημοσίευσης/-εων
Η λήψη ολοκληρώθηκε
+ Προετοιμασία για λήψη…
Γίνεται λήψη της δημοσίευσης…
Γίνεται λήψη πολυμέσων
Γίνεται λήψη εικόνας προφίλ
@@ -285,11 +288,11 @@
Άγνωστο
Αφαίρεση από τα αγαπημένα!
Αντίγραφα ασφαλείας & Επαναφορά
- Auto Backup
- Starting from Android 6, Android\'s Auto Backup feature will upload all app settings, account login data, and favorites onto your Google Drive, which can be restored by reinstalling the app after uninstallation.
- This preference has no effect if Google Play Services is not present, or if Auto Backup is disabled from your device settings. Disabling here does not erase existing backups.
- Enable Auto Backup
- Manual Backup
+ Αυτόματη δημιουργία αντιγράφων ασφαλείας
+ Από το Android 6 κι έπειτα, το χαρακτηριστικό αυτόματης δημιουργίας αντιγράφων ασφαλείας του Android, θα αναφορτώνει όλες τις ρυθμίσεις της εφαρμογής, τα δεδομένα σύνδεσης του λογαριασμού και τα αγαπημένα στο Google Drive σας. Έτσι, θα μπορούν να επαναφερθούν με την επανεγκατάσταση της εφαρμογής μετά την απεγκατάσταση.
+ Αυτή η προτίμηση δεν έχει καμία επίδραση εάν οι υπηρεσίες Google Play δεν είναι παρούσες, ή εάν το αυτόματο αντίγραφο ασφαλείας είναι απενεργοποιημένο από τις ρυθμίσεις της συσκευής σας. Η απενεργοποίηση εδώ δεν διαγράφει τα υπάρχοντα αντίγραφα.
+ Ενεργοποίηση Αυτόματης Δημιουργίας Αντιγράφων Ασφαλείας
+ Μη αυτόματη δημιουργία αντιγράφων ασφαλείας
Δημιουργία αντιγράφου ασφαλείας των ρυθμίσεων της εφαρμογής, των δεδομένων σύνδεσης του λογαριασμού και/ή των αγαπημένων, σε ακρυπτογράφητο ή κρυπτογραφημένο αρχείο για μεταγενέστερη επαναφορά.
Αν δημιουργείτε αντίγραφα ασφαλείας των δεδομένων σύνδεσης λογαριασμού, αντιμετωπίστε το αρχείο ως απόρρητο και κρατήστε το σε ασφαλές μέρος!
Δημιουργία νέου αρχείου αντιγράφου ασφαλείας
@@ -318,7 +321,7 @@
Σχόλιο
Διάταξη
Ροή ιστοριών
- Άνοιγμα δημοσίευσης...
+ Άνοιγμα δημοσίευσης…
Κοινοποίηση
Τρόπος διάταξης
Πλήθος στηλών
@@ -480,13 +483,13 @@
Αντιγραφή απάντησης
Ανάκτηση
Αντίγραφο ασφαλείας
- Select a folder where Barinsta can store downloads and temporary files.\n\nYou can change this later in More > Settings > Downloads.
+ Επιλέξτε έναν φάκελο όπου εκεί θα αποθηκεύονται οι λήψεις και τα προσωρινά αρχεία του Barinsta.\n\nΗ επιλογή σας μπορεί να αλλαχθεί στο Λοιπά> Ρυθμίσεις> Λήψεις.
Το Android έχει αλλάξει τον τρόπο με τον οποίο οι εφαρμογές μπορούν να έχουν πρόσβαση σε αρχεία και καταλόγους στον αποθηκευτικό χώρο. Αυτή τη στιγμή η Barinsta δεν έχει άδεια πρόσβασης στον ακόλουθο φάκελο:
- Permissions for the previously selected folder were revoked by the system:
- The previously selected folder does not exist now:
- Re-select the directory or select a new directory by clicking the button below.
+ Τα δικαιώματα για τον προηγουμένως επιλεγμένο φάκελο ανακλήθηκαν από το σύστημα:
+ Ο προηγουμένως επιλεγμένος φάκελος δεν υπάρχει τώρα:
+ Επιλέξτε ξανά τον φάκελο ή επιλέξτε ένα νέο φάκελο κάνοντας κλικ στο παρακάτω κουμπί.
Δεν επιλέχθηκε φάκελος!
- Please choose a directory from your storage, not a category on the sidebar.
+ Παρακαλώ επιλέξτε έναν φάκελο από τον αποθηκευτικό σας χώρο, όχι μια κατηγορία στην πλαϊνή μπάρα.\n(%s)
Επιτυχία! Παρακαλώ περιμένετε. Εκκίνηση εφαρμογής…
Φάκελος Barinsta
Κορυφή
@@ -496,8 +499,8 @@
Σε πόσους ακριβώς αρέσει
Δε βρέθηκε εικόνα προφίλ!
Είστε βέβαιος για το άνοιγμα αυτού του συνδέσμου;
- Γίνεται αποστολή...
- Κοινοποίηση μέσω
+ Αποστολή…
+ Κοινοποίηση μέσω μηνύματος
Κοινοποίηση συνδέσμου…
- Slide to Cancel
+ Σύρετε για ακύρωση
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 04e9345a..89e41e58 100755
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -19,6 +19,7 @@
Favoritos
Explorar
Comentarios
+ Respuestas
Actividad
Buscar actualizaciones al inicio
Bloquea capturas de pantalla & vista previa de aplicaciones
@@ -67,8 +68,7 @@
¡Sea paciente!
Ver publicación
Ver publicación
- Spotify
- Votar
+ Encuesta
¡Votación exitosa!
¡Ya ha votado!
Comentar
@@ -85,8 +85,10 @@
Deslizador
¡Ya has respondido!
Menciones
+ Pregunta
Esta cuenta es privada
¡No podrás acceder a sus publicaciones después de dejar de seguirle! ¿Estás seguro?
+ ¿Estás seguro/a?
¡Puedes iniciar sesión a través de Más -> Cuenta en la esquina inferior derecha o puedes ver cuentas públicas sin iniciar sesión!
Esta cuenta no tiene publicaciones
¡No existen tales publicaciones!
@@ -101,7 +103,7 @@
Eliminar colección
¿Estás seguro de querer borrar esta colección?
Todos los medios incluidos permanecerán en otras colecciones.
- Añadir a la colección...
+ Añadir a la colección…
Eliminar de la colección
Gustado
Guardado
@@ -180,9 +182,9 @@
Captura de pantalla realizada
No se puede entregar
¡Respuesta del contador de no vistos es nulo!
- Mensaje...
+ Mensaje…
Pulsa y mantén presionado para grabar audio
- Actualizando...
+ Actualizando…
Abandonar chat
¿Salir de este chat?
Expulsar
@@ -194,6 +196,7 @@
¡Descarga los mensajes directamente al teléfono!
Obteniendo publicación(es)
Descarga completada
+ Preparando para descargar…
Descargando publicación…
Descargando multimedia
Descargando foto de perfil
@@ -318,7 +321,7 @@
Comentario
Disposición
Muro de historias
- Abriendo publicación...
+ Abriendo publicación…
Compartir
Estilo de disposición
Número de columnas
@@ -486,7 +489,7 @@
La carpeta seleccionada anteriormente no existe ahora:
Vuelva a seleccionar el directorio o seleccione un nuevo directorio haciendo clic en el botón de abajo.
¡Ninguna carpeta seleccionada!
- Por favor, elija un directorio de su almacenamiento, no una categoría en la barra lateral.
+ Por favor, elija un directorio de su almacenamiento, no una categoría en la barra lateral.\n(%s)
¡Éxito! Por favor espere. Iniciando aplicación…
Carpeta Barinsta
Arriba
@@ -496,7 +499,7 @@
Clic para ver el recuento completo de me gustas
¡No se encontró foto de perfil!
¿Está seguro de querer abrir este enlace?
- Enviando...
+ Enviando…
Compartir por MD
Compartir enlace…
Desliza para cancelar
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 4888ab74..d26f7b3b 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -19,6 +19,7 @@
Gogokoak
Aurkitu
Iruzkinak
+ Erantzunak
Jarduera
Bilatu eguneratzeak abioan
Blokeatu pantaila-argazkiak eta aplikazioaren aurrebista
@@ -29,7 +30,7 @@
Hide muted stories from feed
Markatu MZ ikusita gisa ikusi ondoren
Beste kideek ikusi duzula jakingo dute
- Autoplay video stories
+ Erreproduzitu automatikoki bideoa diren istorioak
Gaitu jarduera-jakinarazpenak
Istorioen jarioaren sailkapena
Error loading profile! Is the username valid? If so, you may be ratelimited.
@@ -42,11 +43,11 @@
Gaia
Hizkuntza
- - %s\nPost
+ - Bidalketa\n%s
- %s\nBidalketa
- - %s Post
+ - Bidalketa %s
- %s Bidalketa
@@ -55,7 +56,7 @@
%s\nJarraituak
Erreproduzitu bideoak automatikoki
- Continue videos in background
+ Mantendu bideoak bigarren planoan
Do not pause videos when the app is out of focus
Mututu bideoak beti
Erakutsi argazki-oina beti
@@ -67,8 +68,7 @@
Itxaron
Ikusi bidalketa
Ikusi bidalketa
- Spotify
- Bozkatu
+ Poll
Bozka ongi bidali da!
Jada bozkatu duzu!
Erantzun
@@ -82,11 +82,13 @@
Erantzun istorioa
Erantzun…
Lehiaketa
- Slider
+ Irristatze-barra
Dagoeneko erantzun duzu!
Aipamenak
+ Question
Kontu hau pribatua da
Ezingo dituzu bidalketak ikusi jarraitzeari utzi ondoren. Ziur zaude?
+ Ziur zaude?
You can log in via More -> Account on the bottom-right corner or you can view public accounts without login!
Kontu honek bidalketarik ez du
Bidalketarik ez!
@@ -96,13 +98,13 @@
Kendu kontu guztiak
This will remove all added accounts from the app!\nTo remove just one account, long tap the account from the account switcher dialog.\nDo you want to continue?
Data-formatua
- Create new collection
+ Bilduma berria sortu
Editatu bildumaren izena
Ezabatu bilduma
Ziur zaude bilduma hau ezabatu nahi duzula?
All contained media will remain in other collections.
- Add to collection...
- Remove from collection
+ Add to collection…
+ Kendu bildumatik
Atsegiteak
Gordeta
Etiketatuta
@@ -146,28 +148,28 @@
Ireki profila
Ikusi istorioa
Ikusi profil-irudia
- Unsupported message type
+ Mezu mota ez da onartzen
Ezabatu mezua
Ikusi GIPHYn
%s shared a post by @%s
- %s shared an image
- %s shared a video
- %s sent a message
- %s shared a gif
- %s shared a sticker
- %s shared a profile: @%s
- %s shared a location: %s
+ %s(e)k irudia partekatu du
+ %s(e)k bideoa partekatu du
+ %s(e)k mezua bidali du
+ %s(e)k gifa partekatu du
+ %s(e)k eranskina partekatu du
+ %s(e)k profila partekatu du: @%s
+ %s(e)k kokalekua partekatu du: %s
%s shared a story highlight by @%s
- %s shared a story by @%s
- %s sent a voice message
+ %s(e)k @%s(r)en istorioa partekatu du
+ %s(e)k ahots-mezua bidali du
%s shared a clip by @%s
- %s shared an IGTV video by @%s
- You replied to their story: %s
- %s replied to your story: %s
- You reacted to their story: %s
- %s reacted to your story: %s
- You mentioned @%s in your story
- %s mentioned you in their story
+ %s(e)k @%s(r)en IGTV bideoa partekatu du
+ Bere istorioari erantzun diozu: %s
+ %s(e)k zure istorioari erantzun dio: %s
+ Bere istorioari erreakzionatu diozu: %s
+ %s(e)k zure istorioari erreakzionatu dio: %s
+ \@%s zure istorioan aipatu duzu
+ %s(e)k bere istorioan aipatu zaitu
Multimedia mota ezezaguna
Multimedia iraungi da!
Iritsi da
@@ -180,9 +182,9 @@
Pantaila-argazkia aterata
Ez da iritsi
Unseen count response is null!
- Mezua...
- Press and hold to record audio
- Eguneratzen...
+ Message…
+ Sakatu eta mantendu audioa grabatzeko
+ Updating…
Utzi txata
Utzi txat hau?
Bota
@@ -194,6 +196,7 @@
Bidalketak telefonora zuzenean deskargatzen ditu
Fetching post(s)
Deskarga burutu da
+ Deskargatzeko prestatzen…
Bidalketa deskargatzen…
Multimedia deskargatzen
Profil-irudia deskargatzen
@@ -202,7 +205,7 @@
Errorea fitxategia deskargatzean
100 bidalketa deskargatu ditzakezu une berean. Ez izan gutiziatsu!
Itzuli iruzkina
- Delete comment
+ Ezabatu iruzkina
Erabiltzaile-izena bilatu nahi duzu?
Traol-hitza bilatu nahi duzu?
Jarraitzaileak
@@ -222,7 +225,7 @@
Onartu eskaera
Baztertu eskaera
Partekatu bidalketa publiko hau…
- This is a private post! Share to those who can view it.
+ Bidalketa pribatua da. Partekatu ikus dezaketen horiekin.
Kategoria hau hutsik dago…
Eguneratze bat eskuragarri dago (%s)
F-Droidetik deskargatu baduzu, bertatik eguneratu behar duzu. GitHubekin ere hori egin behar da.
@@ -240,8 +243,8 @@
%d iruzkin-atsegite
%d erabiltzaile-etiketak
%d atsegite
- %d photos of you
- %d follow requests
+ Ateratzen zaren %d argazki
+ %d jarraipen-eskari
You logged out before clicking this notification?!
Jarioa
Profila
@@ -254,7 +257,7 @@
Ez erakutsi hurrengo eguneratzera arte
Bertsioa
Hasierako pantaila
- Show keyboard on search
+ Erakutsi teklatua bilaketan
Orokorra
Gaia
Deskargak
@@ -301,7 +304,7 @@
Gorde
Argazki-oina
Editatu argazki-oina
- Translate caption
+ Itzuli argazki-oina
Video player timeline
Atsegiten…
Like unsuccessful
@@ -318,7 +321,7 @@
Iruzkina
Antolamendua
Istorioen jarioa
- Bidalketa irekitzen...
+ Opening post…
Partekatu
Diseinua
Zutabe kopurua
@@ -372,8 +375,8 @@
- %d iruzkin
- - %d view
- - %d views
+ - Ikusaldi %d
+ - %d ikusaldi
- Istorio %s
@@ -383,7 +386,7 @@
Izenburua
Kideak
Administratzailea
- Inviter
+ Gonbidatzailea
Mututu mezuak
Mututu aipamenak
Gehitu kideak
@@ -400,35 +403,35 @@
Gehitu
Bidali
Zure buruari erantzuten
- %s(e)ri erantzuten
+ %s(r)i erantzuten
Zure buruari erantzun diozu
Erantzun duzu
- You replied to %s
+ %s(r)i erantzun diozu
Replied to %s
Erantzun dizu
Bere buruari erantzun dio
- You reacted to their story
- Reacted to your story
+ Bere istorioari erreakzionatu diozu
+ Zure istorioari erreakzionatu dio
You mentioned them in your story
- Mentioned you in their story
- You replied to their story
- Replied to your story
- Image has expired
- Image will expire when seen
- Video has expired
- Video will expire when seen
- Message has expired
- Message will expire when seen
- \@%s\'s story
+ Bere istorioan aipatu zaitu
+ Bere istorioari erantzun diozu
+ Zure istorioari erantzun dio
+ Irudia iraungitu da
+ Irudia ikusi bezain pronto iraungituko da
+ Bideoa iraungitu da
+ Bideoa ikusi bezain pronto iraungituko da
+ Mezua iraungitu da
+ Mezua ikusi bezain pronto iraungituko da
+ \@%s(r)en istorioa
\@%s\'s story highlight
- Photo
- Video
- Voice message
- Post
- Approval required to join
- Requests
- Admins only
- Added by %s
+ Argazkia
+ Bideoa
+ Ahots-mezua
+ Bidalketa
+ Batzeko onarpena behar da
+ Eskaerak
+ Administratzaileak soilik
+ %s(e)k gehituta
Admin approval required
An admin approval will be required to add new members to the group
Amaitu txata
@@ -437,14 +440,14 @@
Zain dauden eskariak
Onartu %1s(e)n (%2s) eskaria?
Baztertu
- Accept
+ Onartu
Zu
No pending requests
Checking for new messages
Istorioak
MZ
Jakinarazpenak
- Post
+ Bidalketa
Gaitu MZen jakinarazpenak
Freskatu jarioa automatikoki
Auto refresh every
@@ -460,44 +463,44 @@
Added keyword: %s to filter list
Removed keyword: %s from filter list
Ikusita gisa markatuta
- Delete unsuccessful
+ Ez da ongi deskargatu
Throttled by Instagram because of too many API requests. Wait for some time before retrying.
Errorea
This account has been logged out.
- Login required!
- User is inactive!
+ Saioa hastea beharrezkoa da!
+ Erabiltzailea ez dago aktibo!
Barinsta Crash Report
Select an email app to send crash logs
Not found!
Your IP has been rate limited by Instagram. Wait for an hour and try again. <a href=\"https://redd.it/msxlko\">Learn more.</a>
- Skip this update
- You\'re already on the latest version
+ Saltatu eguneratze hau
+ Jadanik azken bertsioa duzu
Screen order
Other tabs
The tab order will be reflected on next launch
If saved, all DM related features will be disabled on next launch
- Copy caption
- Copy reply
+ Kopiatu argazki-oina
+ Kopiatu erantzuna
Leheneratu
- Backup
+ Babeskopia
Select a folder where Barinsta can store downloads and temporary files.\n\nYou can change this later in More > Settings > Downloads.
Android has changed the way apps can access files and directories on storage. Currently Barinsta does not have permission to access the following folder:
Permissions for the previously selected folder were revoked by the system:
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
- No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
- Success! Please wait. Starting app…
- Barinsta folder
+ Ez da karpetarik hautatu
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
+ Arrakasta! Itxaron, aplikazioa hasten ari da…
+ Barinsta karpeta
Top
- Recent
- Clear
- No Map app found!
+ Azkenak
+ Garbitu
+ Ez da mapa-aplikaziorik aurkitu!
Click to show full like count
- No profile pic found!
- Are you sure you want to open this link?
- Sending...
- Share via DM
+ Irudirik ez da aurkitu!
+ Ziur zaude esteka hau ireki nahi duzula?
+ Sending…
+ Partekatu MZ bidez
Partekatu esteka…
- Slide to Cancel
+ Irristatu uzteko
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 152614d0..40c4a314 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -19,6 +19,7 @@
علاقه مندی ها
کاوش
دیدگاهها
+ Replies
فعالیت
بررسی بروزرسانی هنگام آغاز برنامه
مسدود کردن تصویر از صفحه& پیشنمایش برنامه
@@ -67,8 +68,7 @@
صبور باشید!
دیدن فرسته
دیدن فرسته
- Spotify
- رای دادن
+ Poll
رای با موفقیت بود!
در حال حاظر شما رای داده اید!
پاسخ
@@ -85,9 +85,11 @@
Slider
در حال حاظر شما رای داده اید!
یادآوری ها
+ Question
این اکانت شخصی است
شما امکان دسترسی به پست ها را بعد از آنفالو کردن ندارید!
مطمن هستید؟
+ Are you sure?
می توانید توسط (بیشتر) وارد شوید -> حساب در گوشه پایین سمت راست یا می توانید حساب های عمومی را بدون ورود به سیستم ببینید!
این اکانت پستی ندارد
چنین پست هایی نیست!
@@ -102,7 +104,7 @@
Delete collection
Are you sure you want to delete this collection?
All contained media will remain in other collections.
- Add to collection...
+ Add to collection…
Remove from collection
پسندیده شد
ذخیره شد
@@ -181,9 +183,9 @@
اسکرین شات گرفته شده
نمیتواند ارسال شود
Unseen count response is null!
- پیام...
+ Message…
Press and hold to record audio
- Updating...
+ Updating…
Leave chat
این گفتگو را ترک میکنید؟
اخراج
@@ -195,6 +197,7 @@
دانلود مستقیم پست ها در موبایل!
آوردن پست (ها)
دانلود کامل شده
+ Preparing to download…
دریافت پیک…
دانلود رسانه ها
دانلود عکس پروفایل
@@ -319,7 +322,7 @@
دیدگاه
Layout
Feed stories
- باز کردن پیک...
+ Opening post…
همرسانی
Layout style
Column count
@@ -487,7 +490,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Top
@@ -497,7 +500,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index d1f0fe83..0402c466 100755
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -19,6 +19,7 @@
Favoris
Découvrir
Commentaires
+ Replies
Activité
Rechercher les mises à jours au démarrage
Bloquer les captures d\'écran & l\'aperçu de l\'application
@@ -67,8 +68,7 @@
Soyez patient(e)!
Aperçu
Aperçu
- Spotify
- Vote
+ Poll
Vote réussi !
Vous avez déjà voté !
Répondre
@@ -85,8 +85,10 @@
Curseur
Vous avez déjà répondu !
Mentions
+ Question
Compte privé
Vous ne pourrez plus accéder aux messages après avoir été désabonné! Êtes-vous sûr(e) ?
+ Are you sure?
Vous pouvez vous connecter via Plus -> de Compte en bas à droite ou vous pouvez consulter les comptes publics sans vous connecter !
Ce compte ne contient pas de posts
Aucun post de ce genre !
@@ -101,7 +103,7 @@
Supprimer la collection
Êtes vous sûr·e de vouloir supprimer cette collection ?
Tous les médias contenus resteront dans d\'autres collections.
- Ajouter à la collection...
+ Add to collection…
Retirer de la collection
Aimé
Sauvegardé
@@ -180,9 +182,9 @@
Capture d\'écran effectuée
Impossible de livrer
La réponse du comptage invisible est nulle !
- Message...
+ Message…
Appuyer de manière prolongée pour enregistrer un audio
- Mise à jour en cours...
+ Updating…
Quitter la conversation
Quitter cette conversation ?
Éjecter
@@ -194,6 +196,7 @@
Téléchargez les posts directement sur le téléphone !
Téléchargement de(s) post(s)
Téléchargement terminé
+ Preparing to download…
Entrain de télécharger la publications…
Téléchargement du média en cours
Téléchargement de la photo de profil
@@ -230,7 +233,7 @@
L\'application a planté
Oups.. l\'application a planté, mais ne vous inquiétez pas, vous pouvez envoyer un rapport d\'erreur au développeur pour l\'aider à résoudre le problème :)
Activité
- Archive du story
+ Archive des story
Utilisateurs suggérés
Sélectionnez une image
Envoi en cours…
@@ -318,7 +321,7 @@
Commentaire
Disposition
Flux de stories
- Entrain d\'ouvrir la publication...
+ Opening post…
Partager
Style du modèle
Nombre de colonnes
@@ -486,7 +489,7 @@
Le dossier sélectionné précédemment n\'existe pas :
Ré-sélectionnez le répertoire ou sélectionnez un nouveau répertoire en cliquant sur le bouton ci-dessous.
Aucun dossier sélectionné!
- Veuillez choisir un répertoire dans votre espace de stockage, et non une catégorie dans la barre latérale.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Succès ! Veuillez patienter. Démarrage de l\'application…
Dossier Barinsta
Retour vers le haut
@@ -496,7 +499,7 @@
Cliquez pour voir le compte complet de j\'aimes
Aucune photo de profil trouvée !
Êtes-vous sûr de vouloir ouvrir ce lien ?
- En cours d\'envoi...
+ Sending…
Partager via MP
Partager le lien…
Glisser pour annuler
diff --git a/app/src/main/res/values-hi/arrays.xml b/app/src/main/res/values-hi/arrays.xml
index 9655191d..61fa6c6d 100644
--- a/app/src/main/res/values-hi/arrays.xml
+++ b/app/src/main/res/values-hi/arrays.xml
@@ -31,19 +31,19 @@
- सिस्टम के अनुसार
- बैटरी स्तर के अनुसार
- - गहरा
+ - डार्क
- हल्का
- - Instagram default (Unread then read)
- - From newest to oldest
- - From oldest to newest
+ - सिस्टम निर्धारित (नए से पुराने)
+ - नए से पुराना
+ - पुराने से नया
- कुछ नहीं
- \@
- पर
- - पर
+ - चालू
- \|
- -
@@ -57,7 +57,7 @@
- - secs
- - mins
+ - सेकंड
+ - मिनट
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index b74f6145..e3ae4576 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -19,6 +19,7 @@
पसंदीदा
खोजिए
टिप्पणियाँ
+ जवाब
कार्यकलाप
खुलने पर अपडेट के लिए जाँच करें
स्क्रीनशॉट को ब्लॉक करें & ऐप प्रीव्यू
@@ -29,7 +30,7 @@
फ़ीड से म्यूट की गई स्टोरीस छिपाएं
तुम देखने के बाद सीधा संदेश को \"दिखागया\" लिखा जाएगा
अलग सदस्य जानेंगे कि तुम देखे हो
- Autoplay video stories
+ व्हिडिओ स्टोरी ऑटो प्ले करे
क्रियाकलाप सूचनाएँ दिखायें
फ़ीड स्टोरीज क्रमबद्ध करें
प्रोफ़ाइल लोड करने में एरर! क्या यूजरनाम मान्य है? यदि हां, तो आप सीमित हो सकते हैं.
@@ -67,8 +68,7 @@
धैर्य रखें!
पोस्ट देखें
पोस्ट देखें
- Spotify
- मत दें
+ Poll
मतदान सफल!
आप पहले से ही मत दिये हो!
जवाब
@@ -85,9 +85,11 @@
स्लाइडर
आप पहले से ही उत्तर दिये हो!
उल्लेख
+ Question
यह एकाउॅट निजी है
अनफलो चे बाद आप पोस्ट तक पहुंच नहिं पाओगे!
आप निश्चित हैं?
+ क्या आप सुनिश्चित हैं?
आप लग इन और तरिकें के साथ कर सकते हो -> दक्षिण के निचे कोने में एकाउॅट पर या आप सार्बजनीन एकाउॅट को बिना लग इन के देख सकते हो!
इसी एकाउॅट में कोई पोस्ट नहीं है।
एसे कोई पोस्ट नहीं है!
@@ -102,7 +104,7 @@
संग्रह हटाएं
क्या आप इस संग्रह को मिटाना चाहते हैं?
सभी निहित मीडिया अन्य संग्रहों में बने रहेंगे।
- संग्रह में जोड़ें...
+ Add to collection…
संग्रह से निकालें
पसंद किये
सेव किया
@@ -159,16 +161,16 @@
%s ने @%s. द्वारा एक प्रोफ़ाइल शेयर की
%s ने एक स्थान शेयर किया: %s
%s ने @%s. द्वारा एक कहानी हाइलाइट शेयर की
- %s shared a story by @%s
- %s sent a voice message
- %s shared a clip by @%s
- %s shared an IGTV video by @%s
- You replied to their story: %s
- %s replied to your story: %s
- You reacted to their story: %s
- %s reacted to your story: %s
- You mentioned @%s in your story
- %s mentioned you in their story
+ %s ने @%s. द्वारा एक स्टोरी शेयर की
+ %s ने व्हॉईस मेसेज भेजा
+ %s ने @%s द्वारा एक क्लिप भेजी
+ %s ने @%s द्वारा एक IGTV व्हिडिओ भेजा
+ आपने %s की स्टोरी को रिप्लाय किया
+ %s ने आपकी स्टोरी को रिप्लाय किया %s
+ आपने %s की स्टोरी को रिएक्शन दी
+ %s ने आपकी स्टोरी को रिएक्शन दी: %s
+ आपने @%s को अपनी स्टोरी मे मेनशन किया
+ %s ने आपको उनकी स्टोरी मे मेनशन किया
अज्ञात प्रकार के मिडीआ
मिडीया एक्सपायारड!
वितरित
@@ -181,20 +183,21 @@
स्क्रीनशॉट किया
पहुॅचा नहीं जा सकता
Unseen count response is null!
- Message...
- Press and hold to record audio
- Updating...
- Leave chat
+ Message…
+ ऑडिओ रिकॉर्ड करने के लिये बटन दबाये रखे
+ Updating…
+ चॅट से बाहर निकले
इस बार्तालाप को छोड दें?
बाहर निकालें
अवशेष ब्यबहारकारी
- Invalid user
+ अवैध उपयोगकर्ता
Instagram DM के लिए 60 सेकंड से अधिक के वीडियो अपलोड करने की अनुमति नहीं देता है।
Instagram 60 सेकंड से अधिक समय तक ऑडियो अपलोड करने की अनुमति नहीं देता है।
सीधे डाउनलोड करें
पोस्ट को सिधे अपने फोन पर डाउनलोड करें
पोस्ट(स्) ला रहे हैं
डाउनलोड समाप्त हुआ
+ डाउनलोड करने की तैयारी...
डाउनलोड जारी है…
मिडीया डाउनलोड हो रहा है
प्रोफाइल चित्र डाउनलोड करें
@@ -231,63 +234,64 @@
एप में त्रुटि हुयी।
Oops.. the app crashed, but don\'t worry you can send error report to the developer to help him fix the issue. (:
गतिविधि
- Story archive
- Suggested users
+ स्टोरी आरकाईव
+ सुझायें ऊपयोगकर्ता
चित्र का चयन करें
अपलोड हो रहा है...
आपके पास है:
%d अनुगामी
%d टिप्पणियाँ
%d टिप्पणीयाँ पसन्दीत
- %d usertags
- %d likes
- %d photos of you
- %d follow requests
+ %d युजरटॅग
+ %d लाईक्स
+ %d आपके फोटोज्
+ %d फॉलो रिक्वेस्ट
इस अधिसूचना पर क्लिक करने से पहले आपने लॉग आउट किया?!
फ़ीड
- Profile
- More
- DM
- %d selected
- Successfully logged out!
- Info
- Mark as seen
- Do not show again until next update
+ प्रोफाईल
+ अधिक
+ डी एम
+ %d सिलेक्ट किए हुए
+ सफलतापूर्वक लॉग आउट कर दिया
+ जानकारी
+ पढ़ा गया के रूप मे मार्क करें
+ अगले अपडेट ताक ना दिखाएं
संस्करण
प्रारंभ पृष्ठ
- Show keyboard on search
+ सर्च मे कीबोर्ड दिखाएं
सामान्य
थीम
डाउनलोड
- Locale
+ लोकल
खाता
वर्तमान लॉगिन काम नहीं कर रहा है? बस फिर से खाता जोड़ें।
खाता जोड़ें
- License (English only)
+ लायसेन्स (सिर्फ इंग्लिश)
हमारी वेबसाइट पर जाएं
- Get support, discuss, meet others, and have fun!
+ सपोर्ट करे, बात चीत करे, दुसरोसे मिले, आहे मजे किजिये!
Github मे सोर्स कोड देखें
- Audit, star, report bugs, contribute, and have fun (again)!
- Send feedback by email
- Third-Party Attributions
+ ऑडिट, स्टार, बुग रिपोर्ट करे, योगदान करे, ऑर मजे करे (फिर से)!
+ फीडबॅक ई मेल द्वारा भेजे
+ तीसरे पक्ष के अनुप्रयोग
रिमाइन्डर
- Please use this app responsibly. Downloaded images should only be used for purposes allowed by applicable laws.
+ कृपया यह एप जिम्मेदारी से इस्तेमाल करे.
+डाउनलोड किए हुए इमेजेस सिर्फ नियम पूरक उद्देश से इस्तेमाल करे.
सफेद
काला
हल्के रंग का थीम
गहरे रंग की थीम
कॉफ़ी
- Material Dark
- Added to Favorites!
- Add to Favorites
+ मैटेरियल डार्क
+ फेवरेट में जोड़ा गया
+ फेवरेट के एड करे
खाते
हैशटैग्स
स्थान
अज्ञात
- Removed from Favourites!
- Backup & Restore
- Auto Backup
- Starting from Android 6, Android\'s Auto Backup feature will upload all app settings, account login data, and favorites onto your Google Drive, which can be restored by reinstalling the app after uninstallation.
+ फेवरेट से हटाया
+ बैकअप & रिस्टोर
+ ऑटो बैकअप
+ एंड्रॉयड 6 के आगे, एंड्रॉयड का ऑटो बैकअप फीचर सब एप का बैकअप, अकाउंट लॉग इन डेटा, और फेवरेट गुगल ड्राइव पे होगा, जो एप वापिस इंस्टॉल करते वक्त रिस्टोर होगा अनइंस्टॉल करने के बाद.
This preference has no effect if Google Play Services is not present, or if Auto Backup is disabled from your device settings. Disabling here does not erase existing backups.
Enable Auto Backup
Manual Backup
@@ -319,7 +323,7 @@
Comment
Layout
Feed stories
- Opening post...
+ Opening post…
Share
Layout style
Column count
@@ -346,71 +350,71 @@
Saturation
Sharpen
Exposure
- Center
- Color
- Start
- End
- Bilateral Blur
- Vignette
- Box blur
- Sepia
- Clarendon
- 1977
- Aden
- Reset
- Crop
- Normal
+ मध्य
+ रंग
+ शुरू करें
+ समाप्त
+ बायलॅटरल ब्लर
+ विन्येट
+ बॉक्स ब्लर
+ सिपिया
+ क्लेरेंडन
+ १९७७
+ एडेन
+ रीसेट
+ क्रॉप
+ सामान्य
- - %d like
- - %d likes
+ - %d लाईक्स
+ - %d लाइक्स
- - %d reply
- - %d replies
+ - %d रिप्लाई
+ - %d रिप्लाई
- %d comment
- - %d comments
+ - %d कॉमेंट्स
- - %d view
+ - %d व्यू
- %d views
- %s story
- - %s stories
+ - %s स्टोरीज
- Details
- Title
- Members
- Admin
- Inviter
- Mute messages
- Mute mentions
- Add members
- Search
- Done
- Make Admin
- Remove as Admin
- Edit was unsuccessful
- Message
- Tap to remove
- Forward
- You forwarded a message
- Forwarded a message
- Add
- Send
- Replying to yourself
- Replying to %s
- You replied to yourself
- You replied
- You replied to %s
- Replied to %s
- Replied to you
- Replied to themself
- You reacted to their story
- Reacted to your story
- You mentioned them in your story
+ विवरण
+ शीर्षक:
+ सदस्य
+ एडमिन
+ आमंत्रणकर्ता
+ मेसेज शांत रखे
+ मेनशन शांत रखे
+ सदस्यों को जोड़ें
+ खोजें
+ ठीक
+ एडमिन बनाएं
+ एडमिन से हटाएँ
+ एडिट असफल था
+ मेसेज
+ हटाने के लिए टैप करें
+ फॉरवर्ड करें
+ आपने मेसेज फॉरवर्ड किया
+ मेसेज फॉरवर्ड किया
+ जोड़ें
+ भेजें
+ खुद को रिप्लाई कर रहे
+ %s को रिप्लाई कर रहे
+ खुद को रिप्लाई किया
+ आपने रिप्लाई किया
+ आपने %s को रिप्लाई किया
+ %s को रिप्लाई किया
+ आपको रिप्लाई किया
+ खुद को रिप्लाई किया
+ आपने उनके स्टोरी को रिएक्ट किया
+ आपके स्टोरी को रिएक्ट किया
+ आपने @%s को अपनी स्टोरी मे मेनशन किया
Mentioned you in their story
You replied to their story
Replied to your story
@@ -463,11 +467,11 @@
Marked as seen
Delete unsuccessful
Throttled by Instagram because of too many API requests. Wait for some time before retrying.
- Error
- This account has been logged out.
- Login required!
- User is inactive!
- Barinsta Crash Report
+ एरर
+ यह अकाउंट लॉग आउट हुआ
+ लॉगिन अनिवार्य
+ उपयोगकर्ता निष्क्रिय है
+ Barinsta क्रैश रिपोर्ट
Select an email app to send crash logs
Not found!
Your IP has been rate limited by Instagram. Wait for an hour and try again.
@@ -487,7 +491,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Top
@@ -497,7 +501,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index 84ab0264..5fc2a9fb 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -19,6 +19,7 @@
Favorit
Temukan
Komentar
+ Replies
Aktivitas
Cek pembaruan saat memulai
Block screenshots & app preview
@@ -64,8 +65,7 @@
Mohon bersabar!
Lihat Kiriman
Lihat Kiriman
- Spotify
- Pilih
+ Poll
Berhasil memilih!
Anda sudah memilih!
Tanggapi
@@ -81,8 +81,10 @@
Slider
Anda sudah menjawab!
Sebutan
+ Question
Akun Ini Bersifat Pribadi
Anda tidak akan dapat mengakses kiriman setelah berhenti mengikuti! Anda yakin?
+ Are you sure?
Anda bisa masuk melalui Lebih-> Akun di pojok kanan bawah. Atau anda dapat melihat akun publik tanpa masuk!
Akun ini tidak memiliki kiriman
Kiriman tidak ditemukan!
@@ -97,7 +99,7 @@
Hapus koleksi
Apakah Anda yakin Anda ingin menghapus koleksi ini?
Seluruh media akan tetap berada dalam koleksi-koleksi lain.
- Tambah ke koleksi...
+ Add to collection…
Hapus dari koleksi
Disuka
Tersimpan
@@ -176,9 +178,9 @@
Layar tertangkap
Tidak dapat mengirim
Unseen count response is null!
- Pesan...
+ Message…
Tekan dan tahan untuk merekam
- Memperbarui...
+ Updating…
Tinggalkan obrolan
Tinggalkan obrolan ini?
Keluarkan
@@ -190,6 +192,7 @@
Langsung unduh kiriman ke ponsel!
Mendapatkan kiriman…
Unduhan selesai
+ Preparing to download…
Mengunduh kiriman…
Mengunduh media
Mengunduh foto profil
@@ -314,7 +317,7 @@
Komentar
Tata letak
Umpan cerita
- Membuka kiriman...
+ Opening post…
Bagikan
Gaya tata letak
Jumlah kolom
@@ -477,7 +480,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Top
@@ -487,7 +490,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 43d0d418..e6600907 100755
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -19,6 +19,7 @@
Preferiti
Scopri
Commenti
+ Risposte
Attività
Verifica aggiornamenti all\'avvio
Blocca screenshot & anteprima app
@@ -29,7 +30,7 @@
Nascondi storie silenziate dal feed
Segna il DM come visto dopo la visualizzazione
Altri membri sapranno che lo hai visualizzato
- Autoplay video stories
+ Riproduci automaticamente le storie video
Abilita notifiche attività
Ordinamento storie feed
Errore nel caricamento del profilo! Il nome utente è valido? Se sì, potresti essere considerato limitato.
@@ -67,8 +68,7 @@
Sii paziente!
Visualizza Post
Visualizza Post
- Spotify
- Vota
+ Poll
Votazione riuscita!
Hai già votato!
Rispondi
@@ -85,8 +85,10 @@
Scorrimento
Hai già risposto!
Menzioni
+ Question
Questo Profilo è Privato
Non potrai accederei ai post dopo aver smesso di seguire! Sei sicuro?
+ Sei sicuro?
Puoi accedere tramite Altro -> Profilo nell\'angolo in basso a destra o puoi visualizzare i profili pubblici senza accedere!
Questo Profilo Non ha Post
Nessun Post Simile!
@@ -101,7 +103,7 @@
Elimina raccolta
Sei sicuro di voler eliminare questa raccolta?
Tutti i media contenuti rimarranno in altre raccolte.
- Aggiungi alla raccolta...
+ Add to collection…
Rimuovi dalla raccolta
Piaciuti
Salvati
@@ -180,9 +182,9 @@
Catturato
Impossibile consegnare
Il responso del conteggio non visto è nullo!
- Messaggio...
+ Message…
Tieni premuto per registrare l\'audio
- In aggiornamento...
+ Updating…
Lascia chat
Lasciare questa chat?
Espelli
@@ -194,6 +196,7 @@
Scarica i post direttamente sul telefono!
Recuperando i post
Download completato
+ Preparazione al download…
Scaricando il post…
Download del media
Scaricando l\'immagine del profilo
@@ -318,7 +321,7 @@
Commento
Disposizione
Feed storie
- Aprendo il post...
+ Opening post…
Condividi
Stile disposizione
Conteggio colonne
@@ -486,7 +489,7 @@
La cartella precedentemente selezionata non esiste ora:
Riselezionare la cartella o selezionare una nuova cartella facendo clic sul pulsante qui sotto.
Nessuna cartella selezionata!
- Please choose a directory from your storage, not a category on the sidebar.
+ Scegli una cartella dal tuo archivio, non una categoria sulla barra laterale.\n(%s)
Successo! Attendere prego. Avvio app…
Cartella di Barinsta
Torna su
@@ -496,7 +499,7 @@
Clicca per mostrare il conteggio completo
Nessuna foto profilo trovata!
Sei sicuro di voler aprire questo link?
- Invio in corso...
+ Sending…
Condividi tramite DM
Condivisione link…
Trascinare per cancellare
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 3b3575b9..68c201db 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -19,6 +19,7 @@
お気に入り
発見
コメント
+ Replies
アクティビティ
起動時にアップデートを確認
スクリーンショットとアプリプレビューをブロック
@@ -64,8 +65,7 @@
お待ちください
投稿を表示
投稿を表示
- Spotify
- 投票
+ Poll
投票しました!
すでに投票済みです!
返信する
@@ -81,8 +81,10 @@
スライダー
すでに回答済みです!
メンション
+ Question
このアカウントは非公開です
フォローを解除すると、投稿にアクセスできなくなります。よろしいですか?
+ Are you sure?
右下にある 詳細 -> アカウント でログインすることができます。または、ログインせずに公開アカウントを表示することができます!
このアカウントには投稿がありません
投稿はありません!
@@ -97,7 +99,7 @@
コレクションを削除する
このコレクションを削除してもよろしいですか?
含まれるすべてのメディアは他のコレクションに残ります。
- コレクションに追加する
+ Add to collection…
コレクションから削除する
いいね!
保存
@@ -176,9 +178,9 @@
スクリーンショット撮影済み
配信できません
未読の返信はありません!
- メッセージ...
+ Message…
録音するには長押ししてください
- 更新中...
+ Updating…
チャットから退出する
チャットを終了しますか?
キックする
@@ -190,6 +192,7 @@
投稿を直接ダウンロード!
投稿を取得中
ダウンロードが完了しました
+ Preparing to download…
投稿をダウンロード中…
メディアをダウンロード中
プロフィール画像をダウンロード中
@@ -314,7 +317,7 @@
コメント
レイアウト
フィードのストーリーズ
- 投稿を開いています...
+ Opening post…
共有
レイアウトスタイル
列数
@@ -477,7 +480,7 @@
以前に選択したフォルダは現在存在しません:
ディレクトリを再度選択するか、下のボタンをクリックして新しいディレクトリを選択してください。
フォルダーが選択されていません!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
成功!お待ちください。アプリを起動しています…
Barinstaフォルダ
関連
@@ -487,7 +490,7 @@
Click to show full like count
プロフィール写真が見つかりません!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 1f8ccbf7..4de78257 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -19,6 +19,7 @@
즐겨찾기
발견
댓글
+ Replies
활동
시작시 업데이트 확인
Block screenshots & app preview
@@ -64,8 +65,7 @@
기다려주세요.
게시물 보기
게시물 보기
- Spotify
- 투표
+ Poll
투표 성공!
이미 투표하셨습니다
메시지 보내기
@@ -81,8 +81,10 @@
슬라이더
이미 답변하셨습나다.
언급
+ Question
비공개 계정입니다
언팔로우하면 게시물을 볼 수 없겠습니다. 확실합니까?
+ Are you sure?
You can log in via More -> Account on the bottom-right corner or you can view public accounts without login!
계정에 게시물이 없음
게시물 없음
@@ -97,7 +99,7 @@
컬렉션 삭제
Are you sure you want to delete this collection?
All contained media will remain in other collections.
- 컬렉션에 저장...
+ Add to collection…
컬렉션에서 제거
좋아하는 게시물
저장됨
@@ -138,11 +140,11 @@
미리 보기
Swap Time and Date positions
Cannot delete currently in use account
- Are you sure you want to delete \'%s\'?
+ \"%s\"을(를) 삭제하시겠습니까?
프로필 보기
스토리 보기
프로필 사진 보기
- Unsupported message type
+ 지원되지 않는 메시지 유형
보내기 취소
GIPHY에서 보기
%s shared a post by @%s
@@ -176,9 +178,9 @@
스크린샷
Cannot deliver
Unseen count response is null!
- 메시지...
+ Message…
Press and hold to record audio
- Updating...
+ Updating…
채팅 나가기
이 채팅에서 나가시겠습니까?
Kick
@@ -190,6 +192,7 @@
Downloads posts directly to the phone!
Fetching post(s)
Download completed
+ Preparing to download…
Downloading post…
Downloading media
Downloading profile picture
@@ -314,7 +317,7 @@
댓글 달기
레이아웃
피드 스토리
- 게시물 열기 중...
+ Opening post…
공유
레이아웃 스타일
Column count
@@ -477,7 +480,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
상단
@@ -487,7 +490,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index 8999792c..5da6575f 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -19,17 +19,18 @@
Омилени
Откриј
Коментари
+ Одговори
Активности
Провери за ажурирање
Блокирај слики од екранот & преглед на апликацијата
Превземи објави во папката со кориснички имиња
- Prepend Username to Filename
+ Додади корисничко име при зачувување
Означи ги приказните како видени
Авторот на приказната ќе знае дека сте ја погледнале приказната
- Hide muted stories from feed
+ Сокриј замолчени приказни
Означи порака како видена
Другите членови ќе знаат дека сте ја виделе содржината на пораката
- Autoplay video stories
+ Автоматски гледај видео приказни
Овозможи нотификации
Сортирање на објави
Грешка при вчитување на профилот! Проверете дали корисничкото име е валидно?
@@ -55,8 +56,8 @@
%s\nСледбеници
Autoplay на видеа
- Continue videos in background
- Do not pause videos when the app is out of focus
+ Овозможи играње на видео во позадина
+ Не паузирај видеа кога апликацијата е надвор од фокус
Секогаш гледај видеа без звук
Секогаш прикажувај наслов
Одбери што сакаш да превземеш
@@ -67,8 +68,7 @@
Биди трпелив!
Прегледај Објава
Погледни Објава
- Spotify
- Гласај
+ Poll
Гласањето беше успешно!
Вие веќе гласавте!
Одговори
@@ -85,8 +85,10 @@
Лизгач
Вие веќе одговоривте!
Спомнувања
+ Question
Корисникот има приватен профил
Наме да можете да гледате објави и приказни од овој корисник ако го Одследите! Дали сте сигурни?
+ Дали сте сигурни?
Можете да се најавите преку Повеќе -> Корисничата сметка која се наоѓа долу десно или само можете да гледате Отворени профили без да се логирате!
Овој корисник нема објави
Не постојат такви објави!
@@ -101,7 +103,7 @@
Избриши колекција
Дали сте сигурни дека сакате да ја избришите оваа колекција?
Сите медиуми ќе останат во други колекции.
- Додади во колекција...
+ Add to collection…
Одстрани од колекција
Лајкнато
Зачувано
@@ -180,9 +182,9 @@
Скриншотнато
Неможе да се прати
Одговорот беше null!
- Одговори...
+ Message…
Притисни и задржи за да снимиш аудио порака
- Се ажурира...
+ Updating…
Напушти чат
Дали сакате да го напуштите чатот?
Кикни
@@ -194,6 +196,7 @@
Превземи објави во твојот телефон!
Се превземаат објава(ви)
Преземањето е завршено
+ Preparing to download…
Превземање на Објава…
Се превзема медиум
Се превзема профилната слика
@@ -222,7 +225,7 @@
Одобри барање
Не одобрувај барање
Сподели ја оваа јавна објава до…
- This is a private post! Share to those who can view it.
+ Ова е приватна објава! Споделете ја со оние кои можат да ја видат.
Оваа категорија е празна…
Нова надоградба е присутна! (%s)
Потсетник: Ако ја имате превземено оваа апликација со F-Droid, морате од таму да надоградите! Истото важи и за верзиите од GitHub.
@@ -254,7 +257,7 @@
Прескокни ажурирање
Верзија
Почетна страна
- Show keyboard on search
+ Прикажи тастатура при пребарување
Општо
Изглед
Превземања
@@ -285,11 +288,11 @@
Непознато
Одстрането од Омилени!
Направете Резервна Копија & Враќање
- Auto Backup
- Starting from Android 6, Android\'s Auto Backup feature will upload all app settings, account login data, and favorites onto your Google Drive, which can be restored by reinstalling the app after uninstallation.
- This preference has no effect if Google Play Services is not present, or if Auto Backup is disabled from your device settings. Disabling here does not erase existing backups.
- Enable Auto Backup
- Manual Backup
+ Автоматска резерва
+ Со Андроид верзија 6, Андроид автоматското зачувување на копија ќе зачувува, опции, кориснички информации, омилиени, во Google Drive, и кои ќе бидат вратени со реинсталација на апликацијата.
+ Оваа опција нема ефект, ако немате Google Play Services, или ако Автоматското зачувување на копии е исклучено од подесување. Исклучувањето од тука нема да избрише постоечки резервни копии.
+ Уклучи Автоматски Резерви
+ Рачни Резервни Копии
Зачувај опции од апликацијата, кориснички профил, и/или информации од твоите омилени профили во обичен текст или со енкрипција за подоцна да можеш да ги вратиш.
Ако зачувуваш информации за најавување, третирај го генералниот фајл како многу важен, чувај го на безбедно место!
Креирај новa резервна копија
@@ -318,7 +321,7 @@
Коментирај
Изглед
Приказни
- Отварање на Објава...
+ Opening post…
Сподели
Стил на изглед
Број на колони
@@ -455,49 +458,49 @@
Одговорот на статусот не е ок!
Барањето неуспешно!
Клучен збор
- Enable keyword filter
- Edit keyword filters
- Added keyword: %s to filter list
- Removed keyword: %s from filter list
- Marked as seen
- Delete unsuccessful
- Throttled by Instagram because of too many API requests. Wait for some time before retrying.
+ Вклучи филтер на зборови
+ Уреди филтер на зборови
+ Додаден клучниот збор: %s во листата на филтер
+ Отстранет клучниот збор: %s од листата на филтер
+ Означено како видено
+ Отстранувањето неуспешно
+ Успорување поради Instagram, премногу API пребарувања. Ве молиме почекајте некое време, пред да пробате повторно.
Грешка
Оваа сметка е одјавена.
Потребна е најава!
Корисникот е неактивен!
- Barinsta Crash Report
- Select an email app to send crash logs
- Not found!
- Your IP has been rate limited by Instagram. Wait for an hour and try again. <a href=\"https://redd.it/msxlko\">Learn more.</a>
+ Пријави Грешка
+ Одберете еmail апликација за праќање на грешки
+ Не беше пронајдено!
+ Вашата IP адреса е ограничена од Instagram. Пробајте после еден час повторно. <a href=\"https://redd.it/msxlko\"> Повеќе тука:</a>
Прескокни го ова ажурирање
- You\'re already on the latest version
- Screen order
- Other tabs
- The tab order will be reflected on next launch
- If saved, all DM related features will be disabled on next launch
+ Веќе ја користите најновата верзија
+ Подредување
+ Други менија
+ Редоследот на менија ќе биде аплициран на следно лансирање
+ Ако го зачувате, сите карактеристики поврзани со Директни Пораки ќе бидат исклучени на следно лансирање
Копирај наслов
Копирај одговор
- Restore
- Backup
- Select a folder where Barinsta can store downloads and temporary files.\n\nYou can change this later in More > Settings > Downloads.
- Android has changed the way apps can access files and directories on storage. Currently Barinsta does not have permission to access the following folder:
- Permissions for the previously selected folder were revoked by the system:
- The previously selected folder does not exist now:
- Re-select the directory or select a new directory by clicking the button below.
- No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
- Success! Please wait. Starting app…
- Barinsta folder
- Top
+ Врати
+ Резерви
+ Одберете фолдер каде што Barinsta ќе ги зачувува сите привремени податоци.\n\n Можете да го промените ова подоцна во Повеќе > Опции > Превземања.
+ Андроид 12 го промени начинот на кои апликациите можат да пристапуваат кон податоци од меморија. Засега Barinsta не го подржува ова:
+ Дозволите за претходниот одбран фолдер ќе бидат вратени од страна на системот:
+ Претходно одбраниот фолдер не постои:
+ Одберете пак директориум или направете нов со притскање на копчето подолу.
+ Немате одберено фолдер!
+ Одберете фолдер од вашата меморија, а Не категорија од страна.\n(%s)
+ Успешно! Почекајте...
+ Barinsta фолдер
+ Врв
Најнови
Исчисти
- No Map app found!
- Click to show full like count
- No profile pic found!
- Are you sure you want to open this link?
- Се испраќа...
+ Нема апликација со Мапи!
+ Прилажи прецизен број на допаѓања
+ Слика на профил не беше пронајдена!
+ Дали сте сигурни дека сакате да го отворите овој линк?
+ Sending…
Сподели преку ДП
Сподели линк…
- Slide to Cancel
+ Повлечете за да Откажите
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 7bbfc94f..689de451 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -19,6 +19,7 @@
Favorieten
Ontdekken
Opmerkingen
+ Replies
Activiteit
Controleer op updates bij het opstarten
Screenshots & app voorbeeld blokkeren
@@ -29,7 +30,7 @@
Verberg gedempte verhalen uit feed
Markeer privéberichten als gelezen na bekijken
Andere gebruikers zullen het weten als je het hebt bekeken
- Autoplay video stories
+ Videoverhalen automatisch afspelen
Activiteitmeldingen inschakelen
Feedverhalen sorteren
Fout bij het laden van profiel! Is de gebruikersnaam geldig? Zo ja, dan kan je geratelimiteerd zijn.
@@ -67,8 +68,7 @@
Wees geduldig!
Bekijk Bericht
Bekijk Bericht
- Spotify
- Stem
+ Poll
Stem succesvol!
Je hebt al gestemd!
Reageer
@@ -85,8 +85,10 @@
Schuifregelaar
Je hebt al geantwoord!
Vermeldingen
+ Question
Dit Account is Privé
Je zal geen toegang meer hebben tot berichten na het ontvolgen! Weet je het zeker?
+ Are you sure?
Je kunt inloggen via Meer -> Rechtsonder in je account, of je kunt openbare accounts bekijken zonder in te loggen!
Dit Account heeft Geen Berichten
Geen dergelijke berichten!
@@ -101,7 +103,7 @@
Verwijder collectie
Weet u zeker dat u deze collectie wilt verwijderen?
Alle opgenomen media blijven in andere collecties.
- Aan collectie toevoegen...
+ Add to collection…
Uit collectie verwijderen
Leuk gevonden
Opgeslagen
@@ -119,7 +121,7 @@
Berichten dempen
Verhalen uitzetten
Berichten uitschakelen
- Remove follower
+ Volger verwijderen
Bio kopiëren
Bio vertalen
Wederzijds
@@ -180,9 +182,9 @@
Screenshot genomen
Kan niet afleveren
Ongeziene graaf reactie is nul!
- Bericht...
+ Message…
Ingedrukt houden om audio op te nemen
- Bijwerken...
+ Updating…
Verlaat chat
Deze chat verlaten?
Kick
@@ -194,6 +196,7 @@
Download rechtstreeks naar het apparaat!
Post(s) ophalen
Download voltooid
+ Preparing to download…
Bericht downloaden…
Media downloaden
Profielfoto downloaden
@@ -222,7 +225,7 @@
Verzoek accepteren
Verzoek afwijzen
Deel dit openbare bericht met…
- This is a private post! Share to those who can view it.
+ Dit is een privé bericht! Deel dit met degenen die het kunnen bekijken.
Deze categorie is op de een of andere manier leeg…
Een update is beschikbaar(%s)
Herinnering: Als je via F-Droid hebt gedownload, moet je ook updaten via F-Droid! Hetzelfde geldt voor GitHub.
@@ -254,7 +257,7 @@
Niet meer weergeven tot de volgende update
Versie
Startscherm
- Show keyboard on search
+ Toon toetsenbord bij zoeken
Algemeen
Thema
Downloads
@@ -285,11 +288,11 @@
Onbekend
Verwijderd uit Favorieten!
Backup & Herstel
- Auto Backup
- Starting from Android 6, Android\'s Auto Backup feature will upload all app settings, account login data, and favorites onto your Google Drive, which can be restored by reinstalling the app after uninstallation.
- This preference has no effect if Google Play Services is not present, or if Auto Backup is disabled from your device settings. Disabling here does not erase existing backups.
- Enable Auto Backup
- Manual Backup
+ Automatische back-up
+ Vanaf Android 6, zal Android\'s Auto Backup functie alle app instellingen, account login gegevens, en favorieten uploaden naar uw Google Drive, die kan worden hersteld door het opnieuw installeren van de app na de-installatie.
+ Deze voorkeur heeft geen effect als Google Play Services niet aanwezig is, of als Auto Backup is uitgeschakeld in uw toestelinstellingen. Als u dit uitschakelt, worden bestaande back-ups niet gewist.
+ Automatische back-up inschakelen
+ Handmatige back-up
Back-up maken van Barinsta app-instellingen, accountloggegevens en/of favorieten naar een platte tekst of versleuteld back-up bestand voor later herstellen.
Als u een back-up van accountaanmeldgegevens maakt, het bestand vertrouwelijk behandelt en ergens veilig houdt!
Nieuw back-upbestand maken
@@ -318,7 +321,7 @@
Reageeer
Lay-out
Feed verhalen
- Bericht openen...
+ Opening post…
Delen
Lay-out stijl
Aantal kolommen
@@ -469,7 +472,7 @@
Barinsta Crash Rapport
Selecteer een email app om crashlogs te verzenden
Niet gevonden!
- Your IP has been rate limited by Instagram. Wait for an hour and try again. <a href=\"https://redd.it/msxlko\">Learn more.</a>
+ Je IP is beperkt tot Instagram. Wacht een uur en probeer het opnieuw. <a href=\"https://redd.it/msxlko\">Meer informatie.</a>
Deze update overslaan
Je bent al op de nieuwste versie
Scherm volgorde
@@ -478,26 +481,26 @@
Indien opgeslagen, zullen alle DM gerelateerde functies worden uitgeschakeld bij volgende start
Kopieer opschrift
Antwoord kopiëren
- Restore
+ Herstel
Backup
- Select a folder where Barinsta can store downloads and temporary files.\n\nYou can change this later in More > Settings > Downloads.
- Android has changed the way apps can access files and directories on storage. Currently Barinsta does not have permission to access the following folder:
- Permissions for the previously selected folder were revoked by the system:
- The previously selected folder does not exist now:
- Re-select the directory or select a new directory by clicking the button below.
- No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
- Success! Please wait. Starting app…
- Barinsta folder
+ Selecteer een map waar Barinsta downloads en tijdelijke bestanden kan opslaan.\n\nJe kunt dit later wijzigen in meer > Instellingen > Downloads.
+ Android heeft de manier veranderd waarop apps toegang hebben tot bestanden en mappen op de opslag. Op dit moment heeft Barinsta geen toestemming om toegang te krijgen tot de volgende map:
+ De machtigingen voor de eerder geselecteerde map zijn door het systeem ingetrokken:
+ De eerder geselecteerde map bestaat nu niet meer:
+ Kies de directory opnieuw of kies een nieuwe directory door op de knop hieronder te klikken.
+ Geen map geselecteerd!
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
+ Succes! Even geduld aub. Start app…
+ Barinsta map
Top
Recent
Wissen
Geen Kaartapp gevonden!
- Click to show full like count
+ Klik om volledige like count te tonen
Geen profielfoto gevonden!
- Are you sure you want to open this link?
- Sending...
- Share via DM
- Share link…
- Slide to Cancel
+ Ben je zeker dat je deze link wilt openen?
+ Sending…
+ Delen via DM
+ Link delen…
+ Schuif om te annuleren
diff --git a/app/src/main/res/values-or/arrays.xml b/app/src/main/res/values-or/arrays.xml
index 65ae1c23..e7cf94ad 100644
--- a/app/src/main/res/values-or/arrays.xml
+++ b/app/src/main/res/values-or/arrays.xml
@@ -35,9 +35,9 @@
- ହାଲୁକା
- - Instagram default (Unread then read)
- - From newest to oldest
- - From oldest to newest
+ - ଇନଷ୍ଟାଗ୍ରାମ ଅନୁଯାୟୀ (ପ୍ରଥମେ ଦେଖି ନ ଥିବା ଓ ପରେ ଦେଖିଥିବା)
+ - ନୂତନ ରୁ ପୁରାତନ
+ - ପୁରାତନ ରୁ ନୂତନ
- କିଛି ନୁହେଁ
@@ -57,7 +57,7 @@
- - secs
- - mins
+ - ସେକେଣ୍ଡ
+ - ମିନିଟ୍
diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml
index ea04c162..5119d3ec 100644
--- a/app/src/main/res/values-or/strings.xml
+++ b/app/src/main/res/values-or/strings.xml
@@ -9,7 +9,7 @@
ଲେଖା କପି କରିବାରେ ତ୍ରୁଟି
କ୍ଲିପବୋର୍ଡରେ କପି କରାଗଲା!
ରିପୋର୍ଟ କରନ୍ତୁ
- Protect file with password
+ ପାସୱାର୍ଡ ଦ୍ବାରା ଫାଇଲକୁ ସୁରକ୍ଷିତ କରନ୍ତୁ
ପାସୱାର୍ଡ
ଠିକ୍ ଅଛି
ହଁ
@@ -19,35 +19,36 @@
ପସନ୍ଦିତ
ଖୋଜିବା
ଟିପ୍ପଣୀ
+ ଟିପ୍ପଣୀଗୁଡିକ
କାର୍ଯ୍ୟକଳାପ
ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ
- Block screenshots & app preview
+ ସ୍କ୍ରିନସଟ୍ ଏବଂ app preview ଅବରୋଧ କରନ୍ତୁ
ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ
- Prepend Username to Filename
+ ଏକାଉଣ୍ଟ ନାମକୁ ଫାଇଲନାମ ସହିତ ଯୋଡନ୍ତୁ
କାହାଣୀଗୁଡିକ ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |
କାହାଣୀ ପ୍ରେରକ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ
- Hide muted stories from feed
+ ଫିଡ୍ ରୁ mute ହୋଇଥିବା କାହାଣୀ କୁ ବାଦ ଦିଅନ୍ତୁ
ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ |
ଅନ୍ୟ ସଦସ୍ୟମାନେ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ।
Autoplay video stories
କାର୍ଯ୍ୟକଳାପ ସୂଚନା ଦେଖାନ୍ତୁ
କାହାଣୀଗୁଡିକ ଶ୍ରେଣୀବଦ୍ଧ କରନ୍ତୁ
- Error loading profile! Is the username valid? If so, you may be ratelimited.
- Error loading profile! Is the username valid? Or did they block you?
- Error loading hashtag! Is the name valid?
- Error loading location! Is the URL valid?
+ ପ୍ରୋଫାଇଲ୍ ଲୋଡ୍ କରିବାରେ ତ୍ରୁଟି! ଉପଯୋଗକର୍ତ୍ତା ନାମ ସଠିକ କି? ଯଦି ଠିକ ଅଛି, ତେବେ ଆପଣ instagram ଦ୍ବାରା ସୀମିତ ହୋଇପାରନ୍ତି |
+ ପ୍ରୋଫାଇଲ୍ ଲୋଡ୍ କରିବାରେ ତ୍ରୁଟି! ଉପଯୋଗକର୍ତ୍ତା ନାମ ସଠିକ କି? କିମ୍ବା ସେମାନେ ତୁମକୁ ଅବରୋଧ କରିଛନ୍ତି କି?
+ ହ୍ୟାସଟ୍ୟାଗ୍ ଲୋଡ୍ କରିବାରେ ତ୍ରୁଟି! ନାମ ଠିକ୍ ତ?
+ ସ୍ଥାନ ଲୋଡ୍ କରିବାରେ ତ୍ରୁଟି! ଲିଙ୍କ୍ ଠିକ୍ ତ?
ଡ଼ାଉନଲୋଡ଼ ଫୋଲଡ଼ର ସୃଷ୍ଟି କରିବାରେ ତ୍ରୁଟି ପରିଲକ୍ଷିତ ହେଉଛି।
ନିଜେ ସ୍ଥିର କରିଥିବା ଫୋଲଡର ରେ ରଖ।
ଫୋଲ୍ଡର୍ ଚୟନ କରନ୍ତୁ
ଥିମ
ଭାଷା
- - %s\nPost
- - %s\nPosts
+ - %s\n ପୋଷ୍ଟ
+ - %s\nପୋଷ୍ଟସ
- - %s Post
- - %s Posts
+ - %s ପୋଷ୍ଟ
+ - %s ପୋଷ୍ଟସ
- %s\nFollower
@@ -55,10 +56,10 @@
%s\nଅନୁସରଣ କରୁଛନ୍ତି
ଭିଡ଼ିଓ ସ୍ୱତଃ ଚାଲୁ କର
- Continue videos in background
- Do not pause videos when the app is out of focus
+ ପ୍ରଚ୍ଛଦପଟରେ ଭିଡିଓ ଜାରି ରଖନ୍ତୁ |
+ ଆପ୍ ଫୋକସ୍ ବାହାରେ ଥିବାବେଳେ ଭିଡିଓଗୁଡିକୁ pause କରନ୍ତୁ ନାହିଁ |
ସର୍ବଦା ଭିଡ଼ିଓକୁ ଶବ୍ଦହୀନ ରଖ
- Always show post captions
+ ସର୍ବଦା ପୋଷ୍ଟ କ୍ୟାପସନ୍ ଦେଖାନ୍ତୁ |
ଡାଉନଲୋଡ଼ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ
ସମ୍ପ୍ରତି
ସମସ୍ତ ଆଲବମ
@@ -67,8 +68,7 @@
ଧୈର୍ଯ୍ୟ ରଖନ୍ତୁ!
ପୋଷ୍ଟ ଦେଖନ୍ତୁ
ପୋଷ୍ଟ ଦେଖନ୍ତୁ
- Spotify
- ମତଦାନ କରନ୍ତୁ |
+ Poll
ମତଦାନ ସଫଳ!
ଆପଣ ଭୋଟ୍ ଦେଇସାରିଛନ୍ତି!
ଜବାବ ଦେବା
@@ -85,8 +85,10 @@
ସ୍ଲାଇଡର୍
ଆପଣ ଉତ୍ତର ଦେଇସାରିଛନ୍ତି!
ଉଲ୍ଲେଖଗୁଡିକ
+ Question
ଏହି ଏକାଉଣ୍ଟ ଗୁପ୍ତ ଅଟେ
ଆପଣ ଅନୁସରଣ ନ କଲେ ପୋଷ୍ଟଗୁଡିକୁ ପ୍ରବେଶ କରିବାକୁ ସମର୍ଥ ହେବେ ନାହିଁ! ଆପଣ ନିଶ୍ଚିତ କି?
+ ଆପଣ ନିଶ୍ଚିତ ତ?
ଆପଣ ନିମ୍ନ - ଡାହାଣ କୋଣରେ ଅଧିକ -> ଆକାଉଣ୍ଟ୍ ମାଧ୍ୟମରେ ଲଗ୍ ଇନ୍ କରିପାରିବେ କିମ୍ବା ଆପଣ ଲଗ୍ଇନ୍ ବିନା ସର୍ବସାଧାରଣ ଆକାଉଣ୍ଟ୍ ଦେଖିପାରିବେ |!
ଏହି ଆକାଉଣ୍ଟରେ କୌଣସି ପୋଷ୍ଟ ନାହିଁ |
ଏପରି କୌଣସି ପୋଷ୍ଟ ନାହିଁ!
@@ -96,23 +98,23 @@
ସମସ୍ତ ଏକାଉଣ୍ଟ ହଟାନ୍ତୁ
ଏହା ଆପରୁ ସମସ୍ତ ଯୋଡା ଯାଇଥିବା ଖାତାଗୁଡ଼ିକୁ ଅପସାରଣ କରିବ! \n କେବଳ ଗୋଟିଏ ଖାତା ଅପସାରଣ କରିବା ପାଇଁ ଆକାଉଣ୍ଟ୍ ସୁଇଚର୍ ରୁ ଆକାଉଣ୍ଟକୁ ଲମ୍ବା ଟ୍ୟାପ୍ କରନ୍ତୁ |\nଆପଣ ସମସ୍ତ ଯୋଡା ଯାଇଥିବା ଖାତାଗୁଡ଼ିକୁ ଅପସାରଣ କରିବାକୁ ନିଶ୍ଚିତ ତ?
ଦିନାଙ୍କ ସ୍ୱରୂପ
- Create new collection
- Edit collection name
- Delete collection
- Are you sure you want to delete this collection?
- All contained media will remain in other collections.
- Add to collection...
- Remove from collection
+ ନୂତନ ସଂଗ୍ରହ ସୃଷ୍ଟି କରନ୍ତୁ
+ ସଂଗ୍ରହଟିର ନାମ ବଦଳାନ୍ତୁ
+ ସଂଗ୍ରହ ହଟାନ୍ତୁ
+ କଣ ଆପଣ ଏହି ସଂଗ୍ରହକୁ ବିଲୋପ କରିବାକୁ ନିଶ୍ଚିତ?
+ ଏହା ଧାରଣ କରିଥିବା ସମସ୍ତ ମିଡିଆ ଅନ୍ୟ ସଂଗ୍ରହରେ ରହିବ |
+ Add to collection…
+ ସଂଗ୍ରହରୁ କାଢନ୍ତୁ
ପସନ୍ଦ କରିଛନ୍ତି
ସଞ୍ଚୟ ହେଲା
ଟ୍ୟାଗ୍ କରିଛନ୍ତି
ସନ୍ଦେଶ
- Bookmark
- Follow
- Unfollow
- Favorite
- Block
- Unblock
+ ବୁକମାର୍କ କରନ୍ତୁ
+ ଫୋଲୋ କରନ୍ତୁ
+ ଅନୁସରଣ କରନ୍ତୁ ନାହିଁ
+ ପସନ୍ଦିତ
+ ଅବରୋଧ କରନ୍ତୁ |
+ ଅବରୋଧ ହଟାନ୍ତୁ
Restrict
Unrestrict
Mute stories
@@ -180,9 +182,9 @@
Screenshotted
Cannot deliver
Unseen count response is null!
- Message...
+ Message…
Press and hold to record audio
- Updating...
+ Updating…
Leave chat
Leave this chat?
Kick
@@ -194,6 +196,7 @@
Downloads posts directly to the phone!
Fetching post(s)
Download completed
+ Preparing to download…
Downloading post…
Downloading media
Downloading profile picture
@@ -318,7 +321,7 @@
Comment
Layout
Feed stories
- Opening post...
+ Opening post…
Share
Layout style
Column count
@@ -486,7 +489,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Top
@@ -496,7 +499,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 217dce32..9a157ce7 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -19,6 +19,7 @@
Ulubione
Odkrywaj
Komentarze
+ Odpowiedzi
Aktywność
Sprawdź aktualizacje przy starcie
Blokuj zrzuty ekranu & podgląd aplikacji
@@ -29,7 +30,7 @@
Ukryj wyciszone relacje z kanału
Oznacz wiadomość jako przeczytaną
Inni użytkownicy będą wiedzieli, że to wyświetliłeś
- Autoplay video stories
+ Automatyczne odtwarzanie plików wideo
Włącz powiadomienia o aktywności
Sortowanie relacji
Błąd ładowania profilu! Czy nazwa użytkownika jest prawidłowa? Jeśli tak, możesz być ograniczony.
@@ -73,8 +74,7 @@
Bądź cierpliwy!
Zobacz post
Zobacz post
- Spotify
- Głosuj
+ Poll
Zagłosowano pomyślnie!
Już głosowałeś!
Odpowiedz
@@ -93,8 +93,10 @@
Suwak
Już odpowiedziałeś!
Wzmianki
+ Question
To konto jest prywatne
Nie będziesz mieć dostępu do postów po anulowaniu obserwowania! Jesteś pewny?
+ Jesteś pewien?
Możesz zalogować się za pomocą \"Więcej\" - > \"Konto\" w prawym dolnym rogu lub możesz zobaczyć konta publiczne bez logowania!
To konto nie zawiera postów
Nie ma więcej postów!
@@ -109,7 +111,7 @@
Usunąć kolekcję
Czy na pewno chcesz usunąć tę kolekcję?
Wszystkie media pozostaną w innych kolekcjach.
- Dodaj do kolekcji...
+ Add to collection…
Usuń z kolekcji
Polubione
Zapisane
@@ -188,9 +190,9 @@
Dokonano zrzutu ekranu
Nie dostarczono
Unseen count response is null!
- Wiadomość...
+ Message…
Naciśnij i przytrzymaj, aby nagrać dźwięk
- Aktualizowanie...
+ Updating…
Opuść czat
Opuścić ten czat?
Wyrzuć
@@ -202,6 +204,7 @@
Pobiera posty bezpośrednio na telefon!
Pobieranie post(ów)
Pobieranie zakończone
+ Przygotowywanie do pobrania…
Pobieranie wpisu…
Pobieranie multimediów
Pobieranie zdjęcia profilowego
@@ -326,7 +329,7 @@
Komentarz
Układ
Relacje
- Otwieranie wpisu...
+ Opening post…
Udostępnij
Styl układu
Liczba kolumn
@@ -504,7 +507,7 @@
Poprzednio wybrany folder nie istnieje:
Wybierz ponownie folder lub wybierz now klikając przycisk poniżej.
Nie wybrano folderu!
- Please choose a directory from your storage, not a category on the sidebar.
+ Wybierz katalog z pamięci, a nie kategorię na pasku bocznym.\n(%s)
Sukces! Proszę czekać. Uruchamianie aplikacji…
Folder Barinsta
Najlepsze
@@ -514,7 +517,7 @@
Kliknij, aby wyświetlić pełną liczbę polubień
Nie znaleziono zdjęcia profilowego!
Czy na pewno chcesz otworzyć ten link?
- Wysyłanie...
+ Sending…
Udostępnij przez PW
Udostępnij link…
Przesuń, by anulować
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 092fdffc..1f9a39eb 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -19,6 +19,7 @@
Favoritos
Descobrir
Comentários
+ Respostas
Atividade
Verificar se há atualizações ao iniciar
Bloquear capturas de tela e a pré-visualização do aplicativo
@@ -67,8 +68,7 @@
Tenha paciência!
Ver Publicação
Ver Publicação
- Spotify
- Votar
+ Enquete
Voto enviado!
Você já votou!
Responder
@@ -85,8 +85,10 @@
Deslizante
Você já respondeu!
Menções
+ Pergunta
Esta conta é privada
Você não será capaz de acessar as publicações após deixar de seguir! Tem certeza?
+ Tem certeza?
Você pode fazer login em Mais -> Conta no canto inferior direito ou você pode ver as contas públicas sem fazer login!
Esta conta não tem publicações
Não há publicações!
@@ -101,7 +103,7 @@
Excluir coleção
Tem certeza que quer excluir essa coleção?
Toda a mídia contida permanecerá em outras coleções.
- Adicionar à coleção...
+ Adicionar à coleção…
Remover da coleção
Curtiu
Salvo
@@ -180,9 +182,9 @@
Capturado
Não pode ser entregue
Resposta do contador de não lidas é nula!
- Mensagem...
+ Mensagem…
Aperte e segure para gravar um áudio
- Atualizando...
+ Atualizando…
Sair da conversa
Sair deste chat?
Expulsar
@@ -194,6 +196,7 @@
Baixar as publicações diretamente no telefone!
Buscando publicação(ões)
Download concluído
+ Preparando o download…
Baixando publicação…
Baixando mídia
Baixando foto do perfil
@@ -318,7 +321,7 @@
Comentar
Visualização
Feed de stories
- Abrindo publicação...
+ Abrindo publicação…
Compartilhar
Estilo do layout
Número de colunas
@@ -486,7 +489,7 @@
A pasta selecionada anteriormente não existe agora:
Selecione novamente o diretório ou selecione um novo diretório clicando no botão abaixo.
Nenhuma pasta selecionada!
- Please choose a directory from your storage, not a category on the sidebar.
+ Por favor, escolha um diretório do seu armazenamento, não uma categoria na barra lateral.\n(%s)
Sucesso! Por favor, aguarde. Iniciando o aplicativo…
Pasta Barinsta
Início
@@ -496,7 +499,7 @@
Clique para mostrar a contagem completa de curtidas
Nenhuma foto de perfil encontrada!
Tem certeza que quer abrir este link?
- Enviando...
+ Enviando…
Compartilhar via DM
Compartilhar link…
Deslize para Cancelar
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 4c71160a..07b10200 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -19,6 +19,7 @@
Избранное
Подборка
Комментарии
+ Replies
Активность
Проверять наличие обновлений при запуске
Блокировать скриншоты & превью приложения
@@ -29,7 +30,7 @@
Скрыть заглушённые истории из ленты новостей
Отметить ЛС как увиденные после просмотра
Другие участники узнают, что вы просмотрели его
- Autoplay video stories
+ Автозапуск видео историй
Включить уведомления об активности
Сортировка историй ленты
Ошибка при загрузке профиля! Верно ли имя пользователя? Если это так, то ваш запрос мог быть ограничен сервером.
@@ -73,8 +74,7 @@
Будьте терпеливы!
Посмотреть публикацию
Посмотреть публикацию
- Spotify
- Голосовать
+ Poll
Голосование успешно!
Вы уже проголосовали!
Отреагировать
@@ -93,8 +93,10 @@
Ползунок
Вы уже ответили!
Упоминания
+ Question
Это частная учётная запись
Вы не сможете получить доступ к публикациям после отписки! Вы уверены?
+ Are you sure?
Вы можете войти через Ещё -> Учётная запись в правом нижнем углу или можете просматривать публичные учётные записи без авторизации!
У этой учётной записи нет публикаций
Нет таких публикаций!
@@ -109,7 +111,7 @@
Удалить коллекцию
Вы действительно хотите удалить эту коллекцию?
Всё медиа содержимое сохранится в других коллекциях.
- Добавить в коллекцию...
+ Add to collection…
Удалить из коллекции
Понравилось
Сохранено
@@ -188,9 +190,9 @@
Сделан снимок экрана
Не удаётся доставить
Количество непрочитанных сообщений неизвестно!
- Сообщение...
+ Message…
Нажмите и удерживайте, чтобы записать звук
- Обновление...
+ Updating…
Покинуть чат
Покинуть эту беседу?
Выгнать
@@ -202,6 +204,7 @@
Скачивает публикации прямо на телефон!
Получение публикации(ий)
Скачивание завершено
+ Preparing to download…
Скачивание публикации…
Загрузка медиафайлов
Загрузка изображения профиля
@@ -293,11 +296,11 @@
Неизвестный
Удалено из избранного!
Резервное копирование & Восстановление
- Auto Backup
- Starting from Android 6, Android\'s Auto Backup feature will upload all app settings, account login data, and favorites onto your Google Drive, which can be restored by reinstalling the app after uninstallation.
- This preference has no effect if Google Play Services is not present, or if Auto Backup is disabled from your device settings. Disabling here does not erase existing backups.
- Enable Auto Backup
- Manual Backup
+ Автобэкап
+ Начиная с Android 6, функция автоматического резервного копирования Android будет загружать все настройки приложения, данные для входа в аккаунт, и избранное на диск Google, которые можно восстановить, переустановив приложение после удаления.
+ Эта настройка не имеет эффекта, если службы Google Play отсутствуют, или если Автобэкап отключен в настройках вашего устройства. Отключение не стирает существующие резервные копии.
+ Включить Автобэкап
+ Ручной бэкап
Резервное копирование настроек приложения Barinsta, учётных данных, и/или избранного в виде обычного текста или зашифрованного файла резервной копии для последующего восстановления.
Если вы делаете резервное копирование данных для входа в учётную запись, считайте файл конфиденциальным и храните его где-то в безопасности!
Создать новый файл резервной копии
@@ -326,7 +329,7 @@
Комментировать
Формат
Истории ленты новостей
- Открытие публикации...
+ Opening post…
Поделиться
Внешний вид
Количество столбцов
@@ -504,7 +507,7 @@
Выбранная ранее папка не существует:
Выберите папку заново, нажав на кнопку ниже.
Папка не выбрана!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Успех! Пожалуйста, подождите. Приложение запускается…
Папка Barinsta
В лидерах
@@ -514,7 +517,7 @@
Нажмите, чтобы показать полное число лайков
Картинка профиля не найдена!
Вы действительно хотите открыть эту ссылку?
- Отправляю...
+ Sending…
Поделиться в ЛС
Поделиться ссылкой…
Сдвиньте для отмены
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 36722b21..5164bf75 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -19,6 +19,7 @@
Obľúbené
Prezerať
Komentáre
+ Replies
Aktivita
Kontrolovať aktualizácie pri štarte
Block screenshots & app preview
@@ -73,8 +74,7 @@
Buďte trpezlivý!
Zobraziť príspevok
Zobraziť príspevok
- Spotify
- Hlasovať
+ Poll
Hlasovanie bolo úspešné!
Už si hlasoval!
Odpovedať
@@ -93,8 +93,10 @@
Posúvač
Už si hlasoval!
Zmienky
+ Question
Tento účet je súkromný
Nebudeš môcť pristúpiť k príspevkom po zrušení sledovania. Si si istý?
+ Are you sure?
Môžete sa prihlásiť pomocou Viac -> Účet na dolnom pravom rohu alebo pokračovať v sledovaní verejných profilov bez prihlásenia!
Tento účet nemá žiadne príspevky
Žiadne príspevky!
@@ -109,7 +111,7 @@
Vymazať kolekciu
Si si istý že chceš zmazať túto kolekciu?
All contained media will remain in other collections.
- Add to collection...
+ Add to collection…
Remove from collection
Obľúbené
Uložené
@@ -188,9 +190,9 @@
Urobená snímka obrazovky
Nedá sa odoslať
Unseen count response is null!
- Message...
+ Message…
Press and hold to record audio
- Updating...
+ Updating…
Opustiť chat
Opustiť tento chat?
Vykopnúť
@@ -202,6 +204,7 @@
Stiahnuť príspevky priamo do telefónu!
Získavam príspevky
Sťahovanie bolo dokončené
+ Preparing to download…
Sťahujem príspevok…
Sťahujem médiá
Sťahujem profilovú fotku
@@ -326,7 +329,7 @@
Komentovať
Rozloženie
Príbehy
- Otváram príspevok...
+ Opening post…
Zdieľať
Štýl rozloženia
Počet stĺpcov
@@ -504,7 +507,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Top
@@ -514,7 +517,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 5b3302b8..0114f7d3 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -19,6 +19,7 @@
Favoriter
Upptäck
Kommentarer
+ Replies
Aktivitet
Sök efter uppdatering vid uppstart
Blockera skärmdumpar & förhandsgranskning av appen
@@ -67,8 +68,7 @@
Håll dig lugn!
Visa inlägg
Visa inlägg
- Spotify
- Rösta
+ Poll
Röstningen lyckades!
Du har redan röstat!
Svara
@@ -85,8 +85,10 @@
Slider
Du har redan svarat!
Omnämnanden
+ Question
Det här kontot är Privat
You won\'t be able to access posts after unfollowing! Are you sure?
+ Are you sure?
You can log in via More -> Account on the bottom-right corner or you can view public accounts without login!
Det här kontot har inga inlägg
Inga sådana inlägg!
@@ -101,7 +103,7 @@
Ta bort samling
Är du säker på att du vill ta bort den här samlingen?
All contained media will remain in other collections.
- Lägg till i samlingen...
+ Add to collection…
Ta bort från samling
Gillade
Sparade
@@ -180,9 +182,9 @@
Screenshotted
Kan inte leverera
Unseen count response is null!
- Meddelande...
+ Message…
Tryck och håll in för att spela in ljud
- Uppdaterar...
+ Updating…
Lämna chatt
Lämna den här chatten?
Sparka
@@ -194,6 +196,7 @@
Laddar ner inläggen direkt till telefonen!
Hämtar inlägg(en)
Nerladdningen är färdig
+ Preparing to download…
Laddar ner inlägg…
Laddar ner media
Laddar ner profilbild
@@ -318,7 +321,7 @@
Kommentera
Layout
Feed stories
- Öppnar inlägget...
+ Opening post…
Dela
Layout style
Column count
@@ -486,7 +489,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Topp
@@ -496,7 +499,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index ca6cf993..c146b1d2 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -19,6 +19,7 @@
Favoriler
Keşfet
Yorumlar
+ Replies
Hareketler
Güncellemeleri başlangıçta kontrol et
Block screenshots & app preview
@@ -67,8 +68,7 @@
Sabırlı ol!
Gönderiyi Gör
Gönderiyi Gör
- Spotify
- Oyla
+ Poll
Oylama başarılı!
Zaten oy verdiniz!
Yanıt ver
@@ -85,8 +85,10 @@
Kaydırıcı
Zaten cevapladınız!
Etiketlenenler
+ Question
Bu Hesap Gizlidir
Takipten çıkarsan gönderilere erişemeyeceksin! Emin misin?
+ Are you sure?
Hesabınıza giriş yapmak için sağ alttan Daha Fazla -> Hesap yolunu takip edebilir ya da giriş yapmadan herkese açık profilleri dolaşabilirsin!
Bu Hesabın Gönderisi Yok
Öyle Bir Gönderi Yok!
@@ -101,7 +103,7 @@
Koleksiyonu sil
Bu koleksiyonu silmek istediğinden emin misin?
İçerilen tüm medya diğer koleksiyonlarda kalacak.
- Koleksiyon ekle...
+ Add to collection…
Koleksiyondan kaldır
Beğenilenler
Kaydedilenler
@@ -180,9 +182,9 @@
Ekran görüntüsü alındı
İletilemiyor
Unseen count response is null!
- Mesaj...
+ Message…
Ses kaydetmek için dokun ve basılı tut
- Güncelleniyor...
+ Updating…
Sohbetten ayrıl
Bu sohbetten ayrıl?
Dışarıya At
@@ -194,6 +196,7 @@
Gönderileri direkt telefona indir!
Gönderi(ler) getiriliyor
İndirme tamamlandı
+ Preparing to download…
Gönderi indiriliyor…
Medya indiriliyor
Profil fotoğrafı indiriliyor
@@ -318,7 +321,7 @@
Yorum yap
Yerleşim
Hikaye akışı
- Gönderi açılıyor...
+ Opening post…
Paylaş
Yerleşim biçimi
Sütun sayısı
@@ -486,7 +489,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Top
@@ -496,7 +499,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 747dcabe..e23ab8f0 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -19,6 +19,7 @@
Yêu thích
Khám phá
Bình luận
+ Replies
Hoạt động
Kiểm tra cập nhật khi khởi động
Chặn chụp ảnh màn hình & xem trước ứng dụng
@@ -64,8 +65,7 @@
Hãy kiên nhẫn!
Xem Bài đăng
Xem Bài đăng
- Spotify
- Bình chọn
+ Poll
Bình chọn thành công!
Bạn đã bình chọn rồi!
Trả lời
@@ -81,8 +81,10 @@
Thanh trượt
Bạn đã trả lời rồi!
Đề cập
+ Question
Tài khoản này là riêng tư
Bạn sẽ không thể truy cập vào bài đăng sau khi bỏ theo dõi? Bạn chắc chứ?
+ Are you sure?
Bạn có thể đăng nhập bằng Thêm -> Tài khoản ở góc phải dưới hoặc bạn có thể xem tài khoản công khai mà không cần đăng nhập!
Tài khoản này không có bài viết nào
Không có bài đăng đó!
@@ -97,7 +99,7 @@
Xoá bộ sưu tập
Bạn có chắc muốn xoá bộ sưu tập này chứ?
Tất cả những phương tiện đã lưu sẽ được giữ lại trong bộ sưu tập khác.
- Thêm vào bộ sưu tập...
+ Add to collection…
Xoá khỏi bộ sưu tập
Đã thích
Đã lưu
@@ -176,9 +178,9 @@
Đã chụp màn hình
Không thể gửi
Đánh đấu chưa xem không có giá trị!
- Tin nhắn...
+ Message…
Chạm và giữ để ghi âm
- Đang cập nhật...
+ Updating…
Rời khỏi trò chuyện
Rời khỏi nhóm này?
Đá
@@ -190,6 +192,7 @@
Tải bài viết xuống trực tiếp về điện thoại!
Đang nạp bài viết
Tải xuống hoàn tất
+ Preparing to download…
Đang tải xuống bài viết…
Đang tải xuống phương tiện
Đang tải xuống ảnh đại diện
@@ -314,7 +317,7 @@
Bình luận
Giao diện
Story trên bảng tin
- Đang mở bài đăng...
+ Opening post…
Chia sẻ
Phong cach giao diện
Số cột
@@ -477,7 +480,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
Hàng đầu
@@ -487,7 +490,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 076f9ebf..0a3d00b6 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -19,6 +19,7 @@
最爱
发现
留言
+ 回复
动态
启动时检查更新
屏蔽截图及应用预览
@@ -64,8 +65,7 @@
请耐心等待!
查看帖子
查看帖子
- Spotify
- 投票
+ 投票
投票成功!
您已投票过了!
回复
@@ -81,8 +81,10 @@
滑块
您已回答过了!
提及
+ 问题
私密账户
取消关注后,您将无法访问帖子!您确定吗?
+ 您确定吗?
你可以通过右下角的 更多-> 账户 来登录,或者您无须登录即可查看公开账户!
暂未发帖
无此类帖!
@@ -97,7 +99,7 @@
删除收藏夹
确定想删除这个收藏夹吗?
所有包含的媒体将留在其他收藏夹中。
- 加入收藏夹...
+ 添加到收藏集…
从收藏夹中移除
已赞
已保存
@@ -176,9 +178,9 @@
已截屏
无法发送
未读计数错误!
- 撰写消息...
+ 撰写消息…
长按即可录制语音消息
- 刷新中...
+ 刷新中…
离开聊天
离开此聊天吗?
移除成员
@@ -190,6 +192,7 @@
直接下载至手机!
读取帖子
下载完成
+ 正在准备下载...
帖子下载中…
媒体下载中
大头贴下载中
@@ -314,7 +317,7 @@
评论
布局
快拍动态
- 正在打开帖子...
+ 正在打开帖子…
分享
布局样式
列数
@@ -477,7 +480,7 @@
之前选择的文件夹已不存在:
请点击下面的按钮,来重新选择该目录或选择一个新目录。
未选择文件夹!
- 请选择设备存储中的一个目录,而不是侧边栏上的类别。
+ 请选择设备存储中的一个目录,而不是侧边栏上的类别。\n(%s)
设置成功!请稍候。应用程序启动中…
Barinsta 文件夹
热门
@@ -487,7 +490,7 @@
点击显示完整点赞计数
未找到用户头像!
您确定要打开此链接吗?
- 发送中...
+ 正在发送…
分享至私信
分享链接…
滑动以取消
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index a23a0f16..e4c6bbb4 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -19,6 +19,7 @@
收藏
探索
評論
+ Replies
動態
啟動時檢查更新
阻擋截圖及應用程式預覽
@@ -64,8 +65,7 @@
耐心一點!
查看文章
查看文章
- Spotify
- 投票
+ Poll
投票成功!
您已經投過票了!
回覆
@@ -81,8 +81,10 @@
滑桿
您已經回答了!
提及
+ Question
此帳戶為私人帳戶
取消關注後,您將無法閱讀人家的貼文!你確定嗎?
+ Are you sure?
您可以透過右下角的 「更多」 -> 「新增帳號」 來登入您的帳號,或者以匿名的身分查看公共帳戶!
此帳戶尚未張貼任何文章
找不到此貼文!
@@ -97,7 +99,7 @@
刪除收藏
確定刪除此收藏?
所有包含的多媒體將會保留於其他收藏夾中。
- 新增至收藏...
+ Add to collection…
從收藏中移除
已按讚
已儲存
@@ -176,9 +178,9 @@
已截圖
無法傳送
未讀計數錯誤!
- 撰寫訊息...
+ Message…
長按即可錄製語音訊息
- 更新中...
+ Updating…
離開聊天
離開此聊天室?
踢除
@@ -190,6 +192,7 @@
將貼文直接下載到手機中!
獲取文章中
下載完成
+ Preparing to download…
下載貼文中…
下載媒體中
下載個人圖片中
@@ -314,7 +317,7 @@
評論
佈局
限時動態
- 開啟貼文中…
+ Opening post…
分享
佈局樣式
欄位數量
@@ -477,7 +480,7 @@
The previously selected folder does not exist now:
Re-select the directory or select a new directory by clicking the button below.
No folder selected!
- Please choose a directory from your storage, not a category on the sidebar.
+ Please choose a directory from your storage, not a category on the sidebar.\n(%s)
Success! Please wait. Starting app…
Barinsta folder
熱門
@@ -487,7 +490,7 @@
點選以顯示完整的按讚數量
找不到大頭貼照
您確定要打開此連結嗎?
- 傳送中…
+ Sending…
透過私訊分享
分享連結
Slide to Cancel
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index c017d9bd..23eec836 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -19,4 +19,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 77197e5f..73a01f77 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -32,6 +32,8 @@
Mark DM as seen after viewing
Other members will know you viewed it
Autoplay video stories
+ Display story list by default
+ For viewing stories
Enable activity notifications
Feed stories sort
Error loading profile! Is the username valid? If so, you may be ratelimited.
@@ -69,8 +71,7 @@
Be patient!
View Post
View Post
- Spotify
- Vote
+ Poll
Vote successful!
You have already voted!
Respond
@@ -87,6 +88,7 @@
Slider
You have already answered!
Mentions
+ Question
This Account is Private
You won\'t be able to access posts after unfollowing! Are you sure?
Are you sure?
@@ -104,7 +106,7 @@
Delete collection
Are you sure you want to delete this collection?
All contained media will remain in other collections.
- Add to collection...
+ Add to collection…
Remove from collection
Liked
Saved
@@ -183,9 +185,9 @@
Screenshotted
Cannot deliver
Unseen count response is null!
- Message...
+ Message…
Press and hold to record audio
- Updating...
+ Updating…
Leave chat
Leave this chat?
Kick
@@ -333,7 +335,7 @@
Comment
Layout
Feed stories
- Opening post...
+ Opening post…
Share
Layout style
Column count
@@ -511,7 +513,7 @@
Click to show full like count
No profile pic found!
Are you sure you want to open this link?
- Sending...
+ Sending…
Share via DM
Share link…
Slide to Cancel