mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-31 11:35:34 +00:00 
			
		
		
		
	
							parent
							
								
									e39c129b61
								
							
						
					
					
						commit
						c24fd016b1
					
				| @ -1,89 +0,0 @@ | ||||
| package awais.instagrabber.asyncs; | ||||
| 
 | ||||
| import android.os.AsyncTask; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.io.DataOutputStream; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| import awais.instagrabber.models.StoryModel; | ||||
| import awais.instagrabber.models.stickers.QuizModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| public class QuizAction extends AsyncTask<Integer, Void, Integer> { | ||||
|     private static final String TAG = "QuizAction"; | ||||
| 
 | ||||
|     private final StoryModel storyModel; | ||||
|     private final QuizModel quizModel; | ||||
|     private final String cookie; | ||||
|     private final OnTaskCompleteListener onTaskCompleteListener; | ||||
| 
 | ||||
|     public QuizAction(final StoryModel storyModel, | ||||
|                       final QuizModel quizModel, | ||||
|                       final String cookie, | ||||
|                       final OnTaskCompleteListener onTaskCompleteListener) { | ||||
|         this.storyModel = storyModel; | ||||
|         this.quizModel = quizModel; | ||||
|         this.cookie = cookie; | ||||
|         this.onTaskCompleteListener = onTaskCompleteListener; | ||||
|     } | ||||
| 
 | ||||
|     protected Integer doInBackground(Integer... rawChoice) { | ||||
|         int choice = rawChoice[0]; | ||||
|         final String url = "https://i.instagram.com/api/v1/media/" + storyModel.getStoryMediaId().split("_")[0] + "/" + quizModel.getId() + "/story_quiz_answer/"; | ||||
|         HttpURLConnection urlConnection = null; | ||||
|         try { | ||||
|             JSONObject ogBody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString() | ||||
|                     + "\",\"mutation_token\":\"" + UUID.randomUUID().toString() | ||||
|                     + "\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] | ||||
|                     + "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie) | ||||
|                     + "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) | ||||
|                     + "\"}"); | ||||
|             ogBody.put("answer", String.valueOf(choice)); | ||||
|             String urlParameters = Utils.sign(ogBody.toString()); | ||||
|             urlConnection = (HttpURLConnection) new URL(url).openConnection(); | ||||
|             urlConnection.setRequestMethod("POST"); | ||||
|             urlConnection.setUseCaches(false); | ||||
|             urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); | ||||
|             urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); | ||||
|             if (urlParameters != null) { | ||||
|                 urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); | ||||
|             } | ||||
|             urlConnection.setDoOutput(true); | ||||
|             DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); | ||||
|             wr.writeBytes(urlParameters); | ||||
|             wr.flush(); | ||||
|             wr.close(); | ||||
|             Log.d(TAG, "quiz: " + url + " " + cookie + " " + urlParameters); | ||||
|             urlConnection.connect(); | ||||
|             if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { | ||||
|                 return choice; | ||||
|             } | ||||
|         } catch (Throwable ex) { | ||||
|             Log.e(TAG, "quiz: " + ex); | ||||
|         } finally { | ||||
|             if (urlConnection != null) { | ||||
|                 urlConnection.disconnect(); | ||||
|             } | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(final Integer choice) { | ||||
|         if (onTaskCompleteListener == null || choice == null) return; | ||||
|         onTaskCompleteListener.onTaskComplete(choice); | ||||
|     } | ||||
| 
 | ||||
|     public interface OnTaskCompleteListener { | ||||
|         void onTaskComplete(final int choice); | ||||
|     } | ||||
| } | ||||
| @ -1,88 +0,0 @@ | ||||
| package awais.instagrabber.asyncs; | ||||
| 
 | ||||
| import android.os.AsyncTask; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.io.DataOutputStream; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| import awais.instagrabber.models.StoryModel; | ||||
| import awais.instagrabber.models.stickers.QuestionModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| public class RespondAction extends AsyncTask<String, Void, Boolean> { | ||||
| 
 | ||||
|     private final StoryModel storyModel; | ||||
|     private final QuestionModel questionModel; | ||||
|     private final String cookie; | ||||
|     private final OnTaskCompleteListener onTaskCompleteListener; | ||||
| 
 | ||||
|     public RespondAction(final StoryModel storyModel, | ||||
|                          final QuestionModel questionModel, | ||||
|                          final String cookie, | ||||
|                          final OnTaskCompleteListener onTaskCompleteListener) { | ||||
|         this.storyModel = storyModel; | ||||
|         this.questionModel = questionModel; | ||||
|         this.cookie = cookie; | ||||
|         this.onTaskCompleteListener = onTaskCompleteListener; | ||||
|     } | ||||
| 
 | ||||
|     protected Boolean doInBackground(String... rawChoice) { | ||||
|         final String url = "https://i.instagram.com/api/v1/media/" | ||||
|                 + storyModel.getStoryMediaId().split("_")[0] + "/" + questionModel.getId() + "/story_question_response/"; | ||||
|         HttpURLConnection urlConnection = null; | ||||
|         try { | ||||
|             final JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString() | ||||
|                     + "\",\"mutation_token\":\"" + UUID.randomUUID().toString() | ||||
|                     + "\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] | ||||
|                     + "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie) | ||||
|                     + "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) | ||||
|                     + "\"}"); | ||||
|             String choice = rawChoice[0].replaceAll("\"", ("\\\"")); | ||||
|             ogbody.put("response", choice); | ||||
|             String urlParameters = Utils.sign(ogbody.toString()); | ||||
|             urlConnection = (HttpURLConnection) new URL(url).openConnection(); | ||||
|             urlConnection.setRequestMethod("POST"); | ||||
|             urlConnection.setUseCaches(false); | ||||
|             urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); | ||||
|             urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); | ||||
|             urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); | ||||
|             urlConnection.setDoOutput(true); | ||||
|             DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); | ||||
|             wr.writeBytes(urlParameters); | ||||
|             wr.flush(); | ||||
|             wr.close(); | ||||
|             urlConnection.connect(); | ||||
|             if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|         } catch (Throwable ex) { | ||||
|             Log.e("austin_debug", "respond: " + ex); | ||||
|         } finally { | ||||
|             if (urlConnection != null) { | ||||
|                 urlConnection.disconnect(); | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(final Boolean ok) { | ||||
|         if (onTaskCompleteListener == null) return; | ||||
|         onTaskCompleteListener.onTaskComplete(ok); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public interface OnTaskCompleteListener { | ||||
|         void onTaskComplete(final boolean result); | ||||
|     } | ||||
| } | ||||
| @ -1,69 +0,0 @@ | ||||
| package awais.instagrabber.asyncs; | ||||
| 
 | ||||
| import android.os.AsyncTask; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import java.io.DataOutputStream; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| import awais.instagrabber.models.StoryModel; | ||||
| import awais.instagrabber.models.stickers.PollModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| 
 | ||||
| public class VoteAction extends AsyncTask<Integer, Void, Integer> { | ||||
| 
 | ||||
|     private static final String TAG = "VoteAction"; | ||||
| 
 | ||||
|     private final StoryModel storyModel; | ||||
|     private final PollModel pollModel; | ||||
|     private final String cookie; | ||||
|     private final OnTaskCompleteListener onTaskCompleteListener; | ||||
| 
 | ||||
|     public VoteAction(final StoryModel storyModel, | ||||
|                       final PollModel pollModel, | ||||
|                       final String cookie, | ||||
|                       final OnTaskCompleteListener onTaskCompleteListener) { | ||||
|         this.storyModel = storyModel; | ||||
|         this.pollModel = pollModel; | ||||
|         this.cookie = cookie; | ||||
|         this.onTaskCompleteListener = onTaskCompleteListener; | ||||
|     } | ||||
| 
 | ||||
|     protected Integer doInBackground(Integer... rawChoice) { | ||||
|         int choice = rawChoice[0]; | ||||
|         final String url = "https://www.instagram.com/media/" + storyModel.getStoryMediaId().split("_")[0] + "/" + pollModel.getId() + "/story_poll_vote/"; | ||||
|         try { | ||||
|             final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); | ||||
|             urlConnection.setRequestMethod("POST"); | ||||
|             urlConnection.setUseCaches(false); | ||||
|             urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT); | ||||
|             urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]); | ||||
|             urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); | ||||
|             urlConnection.setRequestProperty("Content-Length", "6"); | ||||
|             urlConnection.setDoOutput(true); | ||||
|             DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); | ||||
|             wr.writeBytes("vote=" + choice); | ||||
|             wr.flush(); | ||||
|             wr.close(); | ||||
|             urlConnection.connect(); | ||||
|             if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { | ||||
|                 return choice; | ||||
|             } | ||||
|             urlConnection.disconnect(); | ||||
|         } catch (Exception ex) { | ||||
|             Log.e(TAG, "Error", ex); | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(final Integer result) { | ||||
|         if (result == null || onTaskCompleteListener == null) return; | ||||
|         onTaskCompleteListener.onTaskComplete(result); | ||||
|     } | ||||
| 
 | ||||
|     public interface OnTaskCompleteListener { | ||||
|         void onTaskComplete(final int choice); | ||||
|     } | ||||
| } | ||||
| @ -11,6 +11,7 @@ import android.os.Handler; | ||||
| import android.util.Log; | ||||
| import android.util.Pair; | ||||
| import android.view.GestureDetector; | ||||
| import android.view.Gravity; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| @ -20,6 +21,9 @@ 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; | ||||
| @ -55,6 +59,7 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.text.NumberFormat; | ||||
| import java.util.Collections; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| @ -63,10 +68,7 @@ import awais.instagrabber.BuildConfig; | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.StoriesAdapter; | ||||
| import awais.instagrabber.asyncs.PostFetcher; | ||||
| import awais.instagrabber.asyncs.QuizAction; | ||||
| import awais.instagrabber.asyncs.RespondAction; | ||||
| import awais.instagrabber.asyncs.SeenAction; | ||||
| import awais.instagrabber.asyncs.VoteAction; | ||||
| import awais.instagrabber.asyncs.direct_messages.CreateThreadAction; | ||||
| import awais.instagrabber.asyncs.direct_messages.DirectThreadBroadcaster; | ||||
| import awais.instagrabber.customviews.helpers.SwipeGestureListener; | ||||
| @ -80,7 +82,10 @@ import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.models.stickers.PollModel; | ||||
| import awais.instagrabber.models.stickers.QuestionModel; | ||||
| import awais.instagrabber.models.stickers.QuizModel; | ||||
| import awais.instagrabber.models.stickers.SliderModel; | ||||
| import awais.instagrabber.repositories.responses.StoryStickerResponse; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.DownloadUtils; | ||||
| import awais.instagrabber.utils.TextUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| @ -117,13 +122,15 @@ public class StoryViewerFragment extends Fragment { | ||||
|     private QuestionModel question; | ||||
|     private String[] mentions; | ||||
|     private QuizModel quiz; | ||||
|     private SliderModel slider; | ||||
|     private MenuItem menuDownload; | ||||
|     private MenuItem menuDm; | ||||
|     private SimpleExoPlayer player; | ||||
|     private boolean isHashtag, isLoc; | ||||
|     private String highlight; | ||||
|     private boolean fetching = false; | ||||
|     private boolean fetching = false, sticking = false; | ||||
|     private int currentFeedStoryIndex; | ||||
|     private double sliderValue; | ||||
|     private StoriesViewModel storiesViewModel; | ||||
|     private boolean shouldRefresh = true; | ||||
|     private StoryViewerFragmentArgs fragmentArgs; | ||||
| @ -190,7 +197,7 @@ public class StoryViewerFragment extends Fragment { | ||||
|                 new AlertDialog.Builder(context) | ||||
|                         .setTitle(R.string.reply_story) | ||||
|                         .setView(input) | ||||
|                         .setPositiveButton(R.string.ok, (d, w) -> new CreateThreadAction(cookie, currentStory.getUserId(), threadId -> { | ||||
|                         .setPositiveButton(R.string.confirm, (d, w) -> new CreateThreadAction(cookie, currentStory.getUserId(), threadId -> { | ||||
|                             try { | ||||
|                                 final DirectThreadBroadcaster.StoryReplyBroadcastOptions options = new DirectThreadBroadcaster.StoryReplyBroadcastOptions( | ||||
|                                         input.getText().toString(), | ||||
| @ -273,6 +280,7 @@ public class StoryViewerFragment extends Fragment { | ||||
| 
 | ||||
|     @SuppressLint("ClickableViewAccessibility") | ||||
|     private void setupListeners() { | ||||
|         final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); | ||||
|         final boolean hasFeedStories; | ||||
|         List<?> models = null; | ||||
|         if (currentFeedStoryIndex >= 0) { | ||||
| @ -297,6 +305,10 @@ public class StoryViewerFragment extends Fragment { | ||||
|         swipeEvent = isRightSwipe -> { | ||||
|             final List<StoryModel> 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; | ||||
| @ -407,15 +419,30 @@ public class StoryViewerFragment extends Fragment { | ||||
|                                     poll.getLeftChoice() + " (" + poll.getLeftCount() + ")", | ||||
|                                     poll.getRightChoice() + " (" + poll.getRightCount() + ")" | ||||
|                             }), (d, w) -> { | ||||
|                                 if (!TextUtils.isEmpty(cookie)) | ||||
|                                     new VoteAction(currentStory, poll, cookie, choice -> { | ||||
|                                         if (choice > -1) { | ||||
|                                             poll.setMyChoice(choice); | ||||
|                                 if (!TextUtils.isEmpty(cookie)) { | ||||
|                                     sticking = true; | ||||
|                                     storiesService.respondToPoll( | ||||
|                                             currentStory.getStoryMediaId().split("_")[0], | ||||
|                                             poll.getId(), | ||||
|                                             w, | ||||
|                                             userIdFromCookie, | ||||
|                                             CookieUtils.getCsrfTokenFromCookie(cookie), | ||||
|                                             new ServiceCallback<StoryStickerResponse>() { | ||||
|                                                 @Override | ||||
|                                                 public void onSuccess(final StoryStickerResponse result) { | ||||
|                                                     sticking = false; | ||||
|                                                     poll.setMyChoice(w); | ||||
|                                                     Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show(); | ||||
|                                             return; | ||||
|                                                 } | ||||
| 
 | ||||
|                                                 @Override | ||||
|                                                 public void onFailure(final Throwable t) { | ||||
|                                                     sticking = false; | ||||
|                                                     Log.e(TAG, "Error responding", t); | ||||
|                                                     Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                     }).execute(w); | ||||
|                                                 } | ||||
|                                             }); | ||||
|                                 } | ||||
|                             }) | ||||
|                             .setPositiveButton(R.string.cancel, null) | ||||
|                             .show(); | ||||
| @ -427,12 +454,29 @@ public class StoryViewerFragment extends Fragment { | ||||
|                 new AlertDialog.Builder(context) | ||||
|                         .setTitle(question.getQuestion()) | ||||
|                         .setView(input) | ||||
|                         .setPositiveButton(R.string.ok, (d, w) -> new RespondAction(currentStory, question, cookie, result -> { | ||||
|                             if (result) { | ||||
|                         .setPositiveButton(R.string.confirm, (d, w) -> { | ||||
|                                 sticking = true; | ||||
|                                 storiesService.respondToQuestion( | ||||
|                                         currentStory.getStoryMediaId().split("_")[0], | ||||
|                                         question.getId(), | ||||
|                                         input.getText().toString(), | ||||
|                                         userIdFromCookie, | ||||
|                                         CookieUtils.getCsrfTokenFromCookie(cookie), | ||||
|                                         new ServiceCallback<StoryStickerResponse>() { | ||||
|                                             @Override | ||||
|                                             public void onSuccess(final StoryStickerResponse result) { | ||||
|                                                 sticking = false; | ||||
|                                                 Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); | ||||
|                             } else | ||||
|                                             } | ||||
| 
 | ||||
|                                             @Override | ||||
|                                             public void onFailure(final Throwable t) { | ||||
|                                                 sticking = false; | ||||
|                                                 Log.e(TAG, "Error responding", t); | ||||
|                                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                         }).execute(input.getText().toString())) | ||||
|                                             } | ||||
|                                         }); | ||||
|                         }) | ||||
|                         .setNegativeButton(R.string.cancel, null) | ||||
|                         .show(); | ||||
|             } else if (tag instanceof String[]) { | ||||
| @ -452,24 +496,119 @@ public class StoryViewerFragment extends Fragment { | ||||
|                 new AlertDialog.Builder(context) | ||||
|                         .setTitle(quiz.getMyChoice() > -1 ? getString(R.string.story_quizzed) : quiz.getQuestion()) | ||||
|                         .setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, choices), (d, w) -> { | ||||
|                             if (quiz.getMyChoice() == -1 && !TextUtils.isEmpty(cookie)) | ||||
|                                 new QuizAction(currentStory, quiz, cookie, choice -> { | ||||
|                                     if (choice > -1) { | ||||
|                                         quiz.setMyChoice(choice); | ||||
|                             if (quiz.getMyChoice() == -1 && !TextUtils.isEmpty(cookie)) { | ||||
|                                 sticking = true; | ||||
|                                 storiesService.respondToQuiz( | ||||
|                                         currentStory.getStoryMediaId().split("_")[0], | ||||
|                                         quiz.getId(), | ||||
|                                         w, | ||||
|                                         userIdFromCookie, | ||||
|                                         CookieUtils.getCsrfTokenFromCookie(cookie), | ||||
|                                         new ServiceCallback<StoryStickerResponse>() { | ||||
|                                             @Override | ||||
|                                             public void onSuccess(final StoryStickerResponse result) { | ||||
|                                                 sticking = false; | ||||
|                                                 quiz.setMyChoice(w); | ||||
|                                                 Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); | ||||
|                                         return; | ||||
|                                             } | ||||
| 
 | ||||
|                                             @Override | ||||
|                                             public void onFailure(final Throwable t) { | ||||
|                                                 sticking = false; | ||||
|                                                 Log.e(TAG, "Error responding", t); | ||||
|                                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                 }).execute(w); | ||||
|                                             } | ||||
|                                         }); | ||||
|                             } | ||||
|                         }) | ||||
|                         .setPositiveButton(R.string.cancel, null) | ||||
|                         .show(); | ||||
|             } else if (tag instanceof SliderModel) { | ||||
|                 slider = (SliderModel) 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.getAverage() * 100; | ||||
|                 input.setProgress(avg.intValue()); | ||||
|                 sliderView.addView(input); | ||||
|                 sliderView.addView(tv); | ||||
|                 if (slider.getMyChoice().isNaN() && slider.canVote()) { | ||||
|                     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.getVoteCount(), | ||||
|                                     slider.getVoteCount(), | ||||
|                                     percentage.format(slider.getAverage()))) | ||||
|                             .setView(sliderView) | ||||
|                             .setPositiveButton(R.string.confirm, (d, w) -> { | ||||
|                                 sticking = true; | ||||
|                                 storiesService.respondToSlider( | ||||
|                                         currentStory.getStoryMediaId().split("_")[0], | ||||
|                                         slider.getId(), | ||||
|                                         sliderValue, | ||||
|                                         userIdFromCookie, | ||||
|                                         CookieUtils.getCsrfTokenFromCookie(cookie), | ||||
|                                         new ServiceCallback<StoryStickerResponse>() { | ||||
|                                             @Override | ||||
|                                             public void onSuccess(final StoryStickerResponse result) { | ||||
|                                                 sticking = false; | ||||
|                                                 slider.setMyChoice(sliderValue); | ||||
|                                                 Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); | ||||
|                                             } | ||||
| 
 | ||||
|                                             @Override | ||||
|                                             public void onFailure(final Throwable t) { | ||||
|                                                 sticking = false; | ||||
|                                                 Log.e(TAG, "Error responding", t); | ||||
|                                                 Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); | ||||
|                                             } | ||||
|                                         }); | ||||
|                             }) | ||||
|                             .setNegativeButton(R.string.cancel, null) | ||||
|                             .show(); | ||||
|                 } | ||||
|                 else { | ||||
|                     input.setEnabled(false); | ||||
|                     tv.setText(getString(R.string.slider_answer, percentage.format(slider.getMyChoice()))); | ||||
|                     new AlertDialog.Builder(context) | ||||
|                             .setTitle(TextUtils.isEmpty(slider.getQuestion()) ? slider.getEmoji() : slider.getQuestion()) | ||||
|                             .setMessage(getResources().getQuantityString(R.plurals.slider_info, | ||||
|                                     slider.getVoteCount(), | ||||
|                                     slider.getVoteCount(), | ||||
|                                     percentage.format(slider.getAverage()))) | ||||
|                             .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() { | ||||
| @ -588,6 +727,10 @@ public class StoryViewerFragment extends Fragment { | ||||
|         binding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE); | ||||
|         binding.quiz.setTag(quiz); | ||||
| 
 | ||||
|         slider = currentStory.getSlider(); | ||||
|         binding.slider.setVisibility(slider != null ? View.VISIBLE : View.GONE); | ||||
|         binding.slider.setTag(slider); | ||||
| 
 | ||||
|         releasePlayer(); | ||||
|         if (isHashtag || isLoc) { | ||||
|             final ActionBar actionBar = fragmentActivity.getSupportActionBar(); | ||||
|  | ||||
| @ -47,6 +47,7 @@ import awais.instagrabber.models.FeedModel; | ||||
| import awais.instagrabber.models.FeedStoryModel; | ||||
| import awais.instagrabber.models.PostsLayoutPreferences; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.CookieUtils; | ||||
| import awais.instagrabber.utils.DownloadUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awais.instagrabber.viewmodels.FeedStoriesViewModel; | ||||
| @ -55,6 +56,7 @@ import awais.instagrabber.webservices.StoriesService; | ||||
| 
 | ||||
| import static androidx.core.content.PermissionChecker.checkSelfPermission; | ||||
| import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { | ||||
|     private static final String TAG = "FeedFragment"; | ||||
| @ -367,9 +369,10 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre | ||||
|     } | ||||
| 
 | ||||
|     private void fetchStories() { | ||||
|         final String cookie = settingsHelper.getString(Constants.COOKIE); | ||||
|         storiesFetching = true; | ||||
|         updateSwipeRefreshState(); | ||||
|         storiesService.getFeedStories(new ServiceCallback<List<FeedStoryModel>>() { | ||||
|         storiesService.getFeedStories(CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback<List<FeedStoryModel>>() { | ||||
|             @Override | ||||
|             public void onSuccess(final List<FeedStoryModel> result) { | ||||
|                 feedStoriesViewModel.getList().postValue(result); | ||||
|  | ||||
| @ -6,6 +6,7 @@ import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.models.stickers.PollModel; | ||||
| import awais.instagrabber.models.stickers.QuestionModel; | ||||
| import awais.instagrabber.models.stickers.QuizModel; | ||||
| import awais.instagrabber.models.stickers.SliderModel; | ||||
| import awais.instagrabber.models.stickers.SwipeUpModel; | ||||
| 
 | ||||
| public final class StoryModel implements Serializable { | ||||
| @ -21,6 +22,7 @@ public final class StoryModel implements Serializable { | ||||
|     private String spotify; | ||||
|     private PollModel poll; | ||||
|     private QuestionModel question; | ||||
|     private SliderModel slider; | ||||
|     private QuizModel quiz; | ||||
|     private SwipeUpModel swipeUp; | ||||
|     private String[] mentions; | ||||
| @ -71,6 +73,10 @@ public final class StoryModel implements Serializable { | ||||
|         return question; | ||||
|     } | ||||
| 
 | ||||
|     public SliderModel getSlider() { | ||||
|         return slider; | ||||
|     } | ||||
| 
 | ||||
|     public QuizModel getQuiz() { | ||||
|         return quiz; | ||||
|     } | ||||
| @ -109,6 +115,10 @@ public final class StoryModel implements Serializable { | ||||
|         this.question = question; | ||||
|     } | ||||
| 
 | ||||
|     public void setSlider(final SliderModel slider) { | ||||
|         this.slider = slider; | ||||
|     } | ||||
| 
 | ||||
|     public void setQuiz(final QuizModel quiz) { | ||||
|         this.quiz = quiz; | ||||
|     } | ||||
|  | ||||
							
								
								
									
										53
									
								
								app/src/main/java/awais/instagrabber/models/stickers/SliderModel.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								app/src/main/java/awais/instagrabber/models/stickers/SliderModel.java
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,53 @@ | ||||
| package awais.instagrabber.models.stickers; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| public final class SliderModel implements Serializable { | ||||
|     private final int voteCount; | ||||
|     private final Double average; | ||||
|     private Double myChoice; | ||||
|     private final boolean canVote; | ||||
|     private final String id, question, emoji; | ||||
| 
 | ||||
|     public SliderModel(final String id, final String question, final String emoji, final boolean canVote, | ||||
|                        final Double average, final int voteCount, final Double myChoice) { | ||||
|         this.id = id; | ||||
|         this.question = question; | ||||
|         this.emoji = emoji; | ||||
|         this.canVote = canVote; | ||||
|         this.average = average; | ||||
|         this.voteCount = voteCount; | ||||
|         this.myChoice = myChoice; | ||||
|     } | ||||
| 
 | ||||
|     public String getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public String getQuestion() { | ||||
|         return question; | ||||
|     } | ||||
| 
 | ||||
|     public String getEmoji() { | ||||
|         return emoji; | ||||
|     } | ||||
| 
 | ||||
|     public boolean canVote() { | ||||
|         return canVote; | ||||
|     } | ||||
| 
 | ||||
|     public int getVoteCount() { | ||||
|         return voteCount; | ||||
|     } | ||||
| 
 | ||||
|     public Double getAverage() { | ||||
|         return average; | ||||
|     } | ||||
| 
 | ||||
|     public Double getMyChoice() { return myChoice; } | ||||
| 
 | ||||
|     public Double setMyChoice(final Double choice) { | ||||
|         this.myChoice = choice; | ||||
|         return choice; | ||||
|     } | ||||
| } | ||||
| @ -2,17 +2,33 @@ package awais.instagrabber.repositories; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import awais.instagrabber.repositories.responses.StoryStickerResponse; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.http.FieldMap; | ||||
| import retrofit2.http.FormUrlEncoded; | ||||
| import retrofit2.http.GET; | ||||
| import retrofit2.http.Header; | ||||
| import retrofit2.http.Path; | ||||
| import retrofit2.http.POST; | ||||
| import retrofit2.http.QueryMap; | ||||
| import retrofit2.http.Url; | ||||
| 
 | ||||
| public interface StoriesRepository { | ||||
| 
 | ||||
|     @GET("graphql/query/") | ||||
|     Call<String> getStories(@QueryMap(encoded = true) Map<String, String> variables); | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/feed/reels_tray/") | ||||
|     Call<String> getStories(@Header("User-Agent") String userAgent, | ||||
|                             @FieldMap Map<String, String> form); | ||||
| 
 | ||||
|     @GET | ||||
|     Call<String> getUserStory(@Header("User-Agent") String userAgent, @Url String url); | ||||
| 
 | ||||
|     @FormUrlEncoded | ||||
|     @POST("/api/v1/media/{storyId}/{stickerId}/{action}/") | ||||
|     Call<StoryStickerResponse> respondToSticker(@Header("User-Agent") String userAgent, | ||||
|                                                 @Path("storyId") String storyId, | ||||
|                                                 @Path("stickerId") String stickerId, | ||||
|                                                 @Path("action") String action, | ||||
|                                                 // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer | ||||
|                                                 @FieldMap Map<String, String> form); | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,20 @@ | ||||
| package awais.instagrabber.repositories.responses; | ||||
| 
 | ||||
| public class StoryStickerResponse { | ||||
|     private final String status; | ||||
| 
 | ||||
|     public StoryStickerResponse(final String status) { | ||||
|         this.status = status; | ||||
|     } | ||||
| 
 | ||||
|     public String getStatus() { | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "StoryStickerResponse{" + | ||||
|                 "status='" + status + '\'' + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -18,6 +18,7 @@ import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| import awais.instagrabber.models.FeedStoryModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| @ -26,9 +27,13 @@ import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.models.stickers.PollModel; | ||||
| import awais.instagrabber.models.stickers.QuestionModel; | ||||
| import awais.instagrabber.models.stickers.QuizModel; | ||||
| import awais.instagrabber.models.stickers.SliderModel; | ||||
| import awais.instagrabber.models.stickers.SwipeUpModel; | ||||
| import awais.instagrabber.repositories.StoriesRepository; | ||||
| import awais.instagrabber.repositories.responses.StoryStickerResponse; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.ResponseBodyUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import retrofit2.Call; | ||||
| import retrofit2.Callback; | ||||
| import retrofit2.Response; | ||||
| @ -44,7 +49,7 @@ public class StoriesService extends BaseService { | ||||
| 
 | ||||
|     private StoriesService() { | ||||
|         final Retrofit retrofit = getRetrofitBuilder() | ||||
|                 .baseUrl("https://www.instagram.com") | ||||
|                 .baseUrl("https://i.instagram.com") | ||||
|                 .build(); | ||||
|         repository = retrofit.create(StoriesRepository.class); | ||||
|     } | ||||
| @ -56,7 +61,7 @@ public class StoriesService extends BaseService { | ||||
|         return instance; | ||||
|     } | ||||
| 
 | ||||
|     public void getFeedStories(final ServiceCallback<List<FeedStoryModel>> callback) { | ||||
|     public void getFeedStories(final String csrfToken, final ServiceCallback<List<FeedStoryModel>> callback) { | ||||
|         if (loadFromMock) { | ||||
|             final Handler handler = new Handler(); | ||||
|             handler.postDelayed(() -> { | ||||
| @ -81,10 +86,13 @@ public class StoriesService extends BaseService { | ||||
|             }, 1000); | ||||
|             return; | ||||
|         } | ||||
|         final Map<String, String> queryMap = new HashMap<>(); | ||||
|         queryMap.put("query_hash", "b7b84d884400bc5aa7cfe12ae843a091"); | ||||
|         queryMap.put("variables", "{\"only_stories\":true,\"stories_prefetch\":false,\"stories_video_dash_manifest\":false}"); | ||||
|         final Call<String> response = repository.getStories(queryMap); | ||||
|         final Map<String, Object> form = new HashMap<>(4); | ||||
|         form.put("reason", "cold_start"); | ||||
|         form.put("_csrftoken", csrfToken); | ||||
|         form.put("_uuid", UUID.randomUUID().toString()); | ||||
|         form.put("supported_capabilities_new", Constants.SUPPORTED_CAPABILITIES); | ||||
|         final Map<String, String> signedForm = Utils.sign(form); | ||||
|         final Call<String> response = repository.getStories(Constants.I_USER_AGENT, signedForm); | ||||
|         response.enqueue(new Callback<String>() { | ||||
|             @Override | ||||
|             public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { | ||||
| @ -106,17 +114,12 @@ public class StoriesService extends BaseService { | ||||
|     private void parseStoriesBody(final String body, final ServiceCallback<List<FeedStoryModel>> callback) { | ||||
|         try { | ||||
|             final List<FeedStoryModel> feedStoryModels = new ArrayList<>(); | ||||
|             final JSONArray feedStoriesReel = new JSONObject(body) | ||||
|                     .getJSONObject("data") | ||||
|                     .getJSONObject(Constants.EXTRAS_USER) | ||||
|                     .getJSONObject("feed_reels_tray") | ||||
|                     .getJSONObject("edge_reels_tray_to_reel") | ||||
|                     .getJSONArray("edges"); | ||||
|             final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray"); | ||||
|             for (int i = 0; i < feedStoriesReel.length(); ++i) { | ||||
|                 final JSONObject node = feedStoriesReel.getJSONObject(i).getJSONObject("node"); | ||||
|                 final JSONObject node = feedStoriesReel.getJSONObject(i); | ||||
|                 final JSONObject user = node.getJSONObject(node.has("user") ? "user" : "owner"); | ||||
|                 final ProfileModel profileModel = new ProfileModel(false, false, false, | ||||
|                                                                    user.getString("id"), | ||||
|                                                                    user.getString("pk"), | ||||
|                                                                    user.getString("username"), | ||||
|                                                                    null, null, null, | ||||
|                                                                    user.getString("profile_pic_url"), | ||||
| @ -240,6 +243,27 @@ public class StoriesService extends BaseService { | ||||
|                                     )); | ||||
|                                 } | ||||
|                             } | ||||
|                             if (data.has("story_cta") && data.has("link_text")) { | ||||
|                                 JSONObject tappableObject = data.getJSONArray("story_cta").getJSONObject(0).getJSONArray("links").getJSONObject(0); | ||||
|                                 String swipeUpUrl = tappableObject.getString("webUri"); | ||||
|                                 if (swipeUpUrl.startsWith("http")) { | ||||
|                                     model.setSwipeUp(new SwipeUpModel(swipeUpUrl, data.getString("link_text"))); | ||||
|                                 } | ||||
|                             } | ||||
|                             if (data.has("story_sliders")) { | ||||
|                                 final JSONObject tappableObject = data.getJSONArray("story_sliders").getJSONObject(0) | ||||
|                                         .optJSONObject("slider_sticker"); | ||||
|                                 if (tappableObject != null) | ||||
|                                     model.setSlider(new SliderModel( | ||||
|                                             String.valueOf(tappableObject.getLong("slider_id")), | ||||
|                                             tappableObject.getString("question"), | ||||
|                                             tappableObject.getString("emoji"), | ||||
|                                             tappableObject.getBoolean("viewer_can_vote"), | ||||
|                                             tappableObject.getDouble("slider_vote_average"), | ||||
|                                             tappableObject.getInt("slider_vote_count"), | ||||
|                                             tappableObject.optDouble("viewer_vote") | ||||
|                                     )); | ||||
|                             } | ||||
|                             JSONArray hashtags = data.optJSONArray("story_hashtags"); | ||||
|                             JSONArray locations = data.optJSONArray("story_locations"); | ||||
|                             JSONArray atmarks = data.optJSONArray("reel_mentions"); | ||||
| @ -283,6 +307,83 @@ public class StoriesService extends BaseService { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private void respondToSticker(final String storyId, | ||||
|                                   final String stickerId, | ||||
|                                   final String action, | ||||
|                                   final String arg1, | ||||
|                                   final String arg2, | ||||
|                                   final String userId, | ||||
|                                   final String csrfToken, | ||||
|                                   final ServiceCallback<StoryStickerResponse> callback) { | ||||
|         final Map<String, Object> form = new HashMap<>(); | ||||
|         form.put("_csrftoken", csrfToken); | ||||
|         form.put("_uid", userId); | ||||
|         form.put("_uuid", UUID.randomUUID().toString()); | ||||
|         form.put("mutation_token", UUID.randomUUID().toString()); | ||||
|         form.put("client_context", UUID.randomUUID().toString()); | ||||
|         form.put("radio_type", "wifi-none"); | ||||
|         form.put(arg1, arg2); | ||||
|         final Map<String, String> signedForm = Utils.sign(form); | ||||
|         final Call<StoryStickerResponse> request = | ||||
|                 repository.respondToSticker(Constants.I_USER_AGENT, storyId, stickerId, action, signedForm); | ||||
|         request.enqueue(new Callback<StoryStickerResponse>() { | ||||
|             @Override | ||||
|             public void onResponse(@NonNull final Call<StoryStickerResponse> call, | ||||
|                                    @NonNull final Response<StoryStickerResponse> response) { | ||||
|                 if (callback != null) { | ||||
|                     callback.onSuccess(response.body()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onFailure(@NonNull final Call<StoryStickerResponse> call, | ||||
|                                   @NonNull final Throwable t) { | ||||
|                 if (callback != null) { | ||||
|                     callback.onFailure(t); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // RespondAction.java | ||||
|     public void respondToQuestion(final String storyId, | ||||
|                                    final String stickerId, | ||||
|                                    final String answer, | ||||
|                                    final String userId, | ||||
|                                    final String csrfToken, | ||||
|                                    final ServiceCallback<StoryStickerResponse> callback) { | ||||
|         respondToSticker(storyId, stickerId, "story_question_response", "response", answer, userId, csrfToken, callback); | ||||
|     } | ||||
| 
 | ||||
|     // QuizAction.java | ||||
|     public void respondToQuiz(final String storyId, | ||||
|                                final String stickerId, | ||||
|                                final int answer, | ||||
|                                final String userId, | ||||
|                                final String csrfToken, | ||||
|                                final ServiceCallback<StoryStickerResponse> callback) { | ||||
|         respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), userId, csrfToken, callback); | ||||
|     } | ||||
| 
 | ||||
|     // VoteAction.java | ||||
|     public void respondToPoll(final String storyId, | ||||
|                                final String stickerId, | ||||
|                                final int answer, | ||||
|                                final String userId, | ||||
|                                final String csrfToken, | ||||
|                                final ServiceCallback<StoryStickerResponse> callback) { | ||||
|         respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); | ||||
|     } | ||||
| 
 | ||||
|     public void respondToSlider(final String storyId, | ||||
|                               final String stickerId, | ||||
|                               final double answer, | ||||
|                               final String userId, | ||||
|                               final String csrfToken, | ||||
|                               final ServiceCallback<StoryStickerResponse> callback) { | ||||
|         respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); | ||||
|     } | ||||
| 
 | ||||
|     private String buildUrl(final String id, final boolean isLoc, final boolean isHashtag, final boolean highlight) { | ||||
|         final String userId = id.replace(":", "%3A"); | ||||
|         final StringBuilder builder = new StringBuilder(); | ||||
|  | ||||
| @ -85,6 +85,16 @@ | ||||
|                 android:visibility="gone" | ||||
|                 app:backgroundTint="@color/btn_blue_background" /> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatButton | ||||
|                 android:id="@+id/slider" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_weight="1" | ||||
|                 android:text="@string/story_slider" | ||||
|                 android:textColor="@color/btn_blue_text_color" | ||||
|                 android:visibility="gone" | ||||
|                 app:backgroundTint="@color/btn_blue_background" /> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatButton | ||||
|                 android:id="@+id/swipeUp" | ||||
|                 android:layout_width="match_parent" | ||||
|  | ||||
| @ -66,9 +66,15 @@ | ||||
|     <string name="respond_story">Respond</string> | ||||
|     <string name="answer_hint">Answer…</string> | ||||
|     <string name="answered_story">Answer successful!</string> | ||||
|     <plurals name="slider_info" comment="For slider stickers in stories, eg. 3 responses averaging 17.38%"> | ||||
|         <item quantity="one">%d response averaging %s</item> | ||||
|         <item quantity="other">%d responses averaging %s</item> | ||||
|     </plurals> | ||||
|     <string name="slider_answer">Your answer: %s</string> | ||||
|     <string name="reply_story">Reply to story</string> | ||||
|     <string name="reply_hint">Reply…</string> | ||||
|     <string name="story_quiz">Quiz</string> | ||||
|     <string name="story_slider">Slider</string> | ||||
|     <string name="story_quizzed">You have already answered!</string> | ||||
|     <string name="story_mentions">Mentions</string> | ||||
|     <string name="priv_acc">This Account is Private</string> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user