answering polls in stories

This commit is contained in:
Austin Huang 2020-07-30 18:19:44 -04:00
parent e1c07c23a7
commit 71402cd164
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
13 changed files with 207 additions and 31 deletions

View File

@ -34,6 +34,7 @@ Not compatible with pre-16.6 versions (including alpha).
Remember to read the [wiki](https://github.com/austinhuang0131/instagrabber/wiki) for more info! Remember to read the [wiki](https://github.com/austinhuang0131/instagrabber/wiki) for more info!
[![Open Source Love svg3](https://badges.frapsoft.com/os/v3/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badges/) [![Open Source Love svg3](https://badges.frapsoft.com/os/v3/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badges/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)
[![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE) [![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE)
[![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/austinhuang0131/instagrabber)](https://snyk.io/test/github/austinhuang0131/instagrabber) [![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/austinhuang0131/instagrabber)](https://snyk.io/test/github/austinhuang0131/instagrabber)
[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/austinhuang0131/instagrabber)](https://lgtm.com/projects/g/austinhuang0131/instagrabber) [![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/austinhuang0131/instagrabber)](https://lgtm.com/projects/g/austinhuang0131/instagrabber)

View File

@ -15,10 +15,12 @@ import android.util.Pair;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.view.GestureDetectorCompat; import androidx.core.view.GestureDetectorCompat;
@ -36,8 +38,11 @@ import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.source.ProgressiveMediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import awais.instagrabber.BuildConfig; import awais.instagrabber.BuildConfig;
import awais.instagrabber.R; import awais.instagrabber.R;
@ -47,6 +52,7 @@ import awais.instagrabber.customviews.helpers.SwipeGestureListener;
import awais.instagrabber.databinding.ActivityStoryViewerBinding; import awais.instagrabber.databinding.ActivityStoryViewerBinding;
import awais.instagrabber.interfaces.SwipeEvent; import awais.instagrabber.interfaces.SwipeEvent;
import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.FeedStoryModel;
import awais.instagrabber.models.PollModel;
import awais.instagrabber.models.PostModel; import awais.instagrabber.models.PostModel;
import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.StoryModel;
import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.enums.MediaItemType;
@ -79,6 +85,7 @@ public final class StoryViewer extends BaseLanguageActivity {
private SimpleExoPlayer player; private SimpleExoPlayer player;
private SwipeEvent swipeEvent; private SwipeEvent swipeEvent;
private MenuItem menuDownload; private MenuItem menuDownload;
private PollModel poll;
private StoryModel currentStory; private StoryModel currentStory;
private String url, username; private String url, username;
private int slidePos = 0, lastSlidePos = 0; private int slidePos = 0, lastSlidePos = 0;
@ -121,8 +128,6 @@ public final class StoryViewer extends BaseLanguageActivity {
@Override @Override
public void onSwipe(final boolean isRightSwipe) { public void onSwipe(final boolean isRightSwipe) {
Log.d("austin_debug", "swipe: "+(isRightSwipe ? "backward " : "forward ") + slidePos + "/" + storiesLen + " "
+ (slidePos == storiesLen - 1 && isRightSwipe == false) + " " + intent.hasExtra(Constants.FEED));
if (storyModels != null && storiesLen > 0) { if (storyModels != null && storiesLen > 0) {
if (((slidePos + 1 >= storiesLen && isRightSwipe == false) || (slidePos == 0 && isRightSwipe == true)) if (((slidePos + 1 >= storiesLen && isRightSwipe == false) || (slidePos == 0 && isRightSwipe == true))
&& intent.hasExtra(Constants.FEED)) { && intent.hasExtra(Constants.FEED)) {
@ -195,6 +200,30 @@ public final class StoryViewer extends BaseLanguageActivity {
.putExtra(Constants.EXTRAS_POST, new PostModel(tag.toString()))); .putExtra(Constants.EXTRAS_POST, new PostModel(tag.toString())));
}); });
storyViewerBinding.interactStory.setOnClickListener(v -> {
final Object tag = v.getTag();
if (tag instanceof PollModel) {
poll = (PollModel) tag;
if (poll.getMyChoice() > -1)
new AlertDialog.Builder(this).setTitle(R.string.voted_story_poll)
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new String[]{
(poll.getMyChoice() == 0 ? "" : "") + poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
(poll.getMyChoice() == 1 ? "" : "") + poll.getRightChoice() + " (" + poll.getRightCount() + ")"
}), null)
.setPositiveButton(R.string.ok, null)
.show();
else new AlertDialog.Builder(this).setTitle(poll.getQuestion())
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new String[]{
poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
poll.getRightChoice() + " (" + poll.getRightCount() + ")"
}), (d, w) -> {
new VoteAction().execute(w);
})
.setPositiveButton(R.string.cancel, null)
.show();
}
});
storiesAdapter.setData(storyModels); storiesAdapter.setData(storyModels);
if (storyModels.length > 1) storyViewerBinding.storiesList.setVisibility(View.VISIBLE); if (storyModels.length > 1) storyViewerBinding.storiesList.setVisibility(View.VISIBLE);
@ -368,9 +397,14 @@ public final class StoryViewer extends BaseLanguageActivity {
storyViewerBinding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE); storyViewerBinding.viewStoryPost.setVisibility(shortCode != null ? View.VISIBLE : View.GONE);
storyViewerBinding.viewStoryPost.setTag(shortCode); storyViewerBinding.viewStoryPost.setTag(shortCode);
final PollModel poll = currentStory.getPoll();
storyViewerBinding.interactStory.setVisibility(poll != null ? View.VISIBLE : View.GONE);
storyViewerBinding.interactStory.setText(R.string.vote_story_poll);
storyViewerBinding.interactStory.setTag(poll);
releasePlayer(); releasePlayer();
final Intent intent = getIntent(); final Intent intent = getIntent();
if (intent.hasExtra(Constants.EXTRAS_HASHTAG)) { if (intent.getBooleanExtra(Constants.EXTRAS_HASHTAG, false)) {
storyViewerBinding.toolbar.toolbar.setTitle(currentStory.getUsername() + " (" + intent.getStringExtra(Constants.EXTRAS_USERNAME) + ")"); storyViewerBinding.toolbar.toolbar.setTitle(currentStory.getUsername() + " (" + intent.getStringExtra(Constants.EXTRAS_USERNAME) + ")");
storyViewerBinding.toolbar.toolbar.setOnClickListener(v -> { storyViewerBinding.toolbar.toolbar.setOnClickListener(v -> {
searchUsername(currentStory.getUsername()); searchUsername(currentStory.getUsername());
@ -408,4 +442,46 @@ public final class StoryViewer extends BaseLanguageActivity {
} }
return returnvalue; return returnvalue;
} }
class VoteAction extends AsyncTask<Integer, Void, Void> {
int ok = -1;
String action;
protected Void doInBackground(Integer... rawchoice) {
int choice = rawchoice[0];
final String url = "https://www.instagram.com/media/"+currentStory.getStoryMediaId()+"/"+poll.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",
settingsHelper.getString(Constants.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) {
ok = choice;
}
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "vote: " + ex);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (ok > -1) {
poll.setMyChoice(ok);
Toast.makeText(getApplicationContext(), R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
}
}
}
} }

View File

@ -425,8 +425,6 @@ public final class FeedAdapter extends RecyclerView.Adapter<FeedItemViewHolder>
if (btnMute != null) btnMute.setVisibility(View.VISIBLE); if (btnMute != null) btnMute.setVisibility(View.VISIBLE);
final PlayerView playerView = new PlayerView(context); final PlayerView playerView = new PlayerView(context);
Log.d("austin_debug","1");
player = new SimpleExoPlayer.Builder(context).build(); player = new SimpleExoPlayer.Builder(context).build();
playerView.setPlayer(player); playerView.setPlayer(player);

View File

@ -177,7 +177,7 @@ public final class DiscoverFetcher extends AsyncTask<Void, Void, DiscoverItemMod
Utils.getThumbnailUrl(media, mediaType)); Utils.getThumbnailUrl(media, mediaType));
Utils.checkExistence(downloadDir, customDir, username, Utils.checkExistence(downloadDir, customDir, username,
mediaType == MediaItemType.MEDIA_TYPE_SLIDER, -1, model); mediaType == MediaItemType.MEDIA_TYPE_SLIDER, model);
return model; return model;
} }

View File

@ -26,7 +26,6 @@ public final class LocationFetcher extends AsyncTask<Void, Void, LocationModel>
private final String idSlug; private final String idSlug;
public LocationFetcher(String idSlug, FetchListener<LocationModel> fetchListener) { public LocationFetcher(String idSlug, FetchListener<LocationModel> fetchListener) {
Log.d("austin_debug", idSlug);
// idSlug = id + "/" + slug // idSlug = id + "/" + slug
this.idSlug = idSlug; this.idSlug = idSlug;
this.fetchListener = fetchListener; this.fetchListener = fetchListener;

View File

@ -95,7 +95,7 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
postModel.setCommentsCount(commentsCount); postModel.setCommentsCount(commentsCount);
postModel.setCommentsEndCursor(endCursor); postModel.setCommentsEndCursor(endCursor);
Utils.checkExistence(downloadDir, customDir, username, false, -1, postModel); Utils.checkExistence(downloadDir, customDir, username, false, postModel);
result = new ViewerPostModel[]{postModel}; result = new ViewerPostModel[]{postModel};
@ -119,7 +119,7 @@ public final class PostFetcher extends AsyncTask<Void, Void, ViewerPostModel[]>
media.optJSONObject("location")); media.optJSONObject("location"));
postModels[i].setSliderDisplayUrl(node.getString("display_url")); postModels[i].setSliderDisplayUrl(node.getString("display_url"));
Utils.checkExistence(downloadDir, customDir, username, true, i, postModels[i]); Utils.checkExistence(downloadDir, customDir, username, true, postModels[i]);
} }
postModels[0].setCommentsCount(commentsCount); postModels[0].setCommentsCount(commentsCount);

View File

@ -115,7 +115,7 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
mediaNode.getLong("taken_at_timestamp"), mediaNode.optBoolean("viewer_has_liked"), mediaNode.getLong("taken_at_timestamp"), mediaNode.optBoolean("viewer_has_liked"),
mediaNode.optBoolean("viewer_has_saved"), mediaNode.getJSONObject("edge_liked_by").getLong("count")); mediaNode.optBoolean("viewer_has_saved"), mediaNode.getJSONObject("edge_liked_by").getLong("count"));
Utils.checkExistence(downloadDir, customDir, username, isSlider, -1, models[i]); Utils.checkExistence(downloadDir, customDir, username, isSlider, models[i]);
} }
if (models[models.length - 1] != null) if (models[models.length - 1] != null)

View File

@ -12,6 +12,7 @@ import java.net.URL;
import awais.instagrabber.BuildConfig; import awais.instagrabber.BuildConfig;
import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.models.PollModel;
import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.StoryModel;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
@ -34,8 +35,8 @@ public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]
@Override @Override
protected StoryModel[] doInBackground(final Void... voids) { protected StoryModel[] doInBackground(final Void... voids) {
StoryModel[] result = null; StoryModel[] result = null;
final String url = "https://www.instagram.com/graphql/query/?query_hash=52a36e788a02a3c612742ed5146f1676&variables=" + final String url = "https://www.instagram.com/graphql/query/?query_hash=90709b530ea0969f002c86a89b4f2b8d&variables=" +
"{\"precomposed_overlay\":false," "{\"precomposed_overlay\":false,\"show_story_viewer_list\":false,\"stories_video_dash_manifest\":false,"
+(!Utils.isEmpty(hashtag) ? ("\"tag_names\":\""+hashtag+"\"}") : ( +(!Utils.isEmpty(hashtag) ? ("\"tag_names\":\""+hashtag+"\"}") : (
location ? "\"location_ids\":[\""+id.split("/")[0]+"\"]}" : "\"reel_ids\":[\"" + id + "\"]}")); location ? "\"location_ids\":[\""+id.split("/")[0]+"\"]}" : "\"reel_ids\":[\"" + id + "\"]}"));
@ -76,9 +77,19 @@ public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]
for (int j = 0; j < tappableLength; ++j) { for (int j = 0; j < tappableLength; ++j) {
JSONObject tappableObject = tappableObjects.getJSONObject(j); JSONObject tappableObject = tappableObjects.getJSONObject(j);
if (tappableObject.optString("__typename").equals("GraphTappableFeedMedia")) { if (tappableObject.optString("__typename").equals("GraphTappableFeedMedia")) {
tappableObject = tappableObject.getJSONObject("media"); models[i].setTappableShortCode(tappableObject.getJSONObject("media").getString(Constants.EXTRAS_SHORTCODE));
models[i].setTappableShortCode(tappableObject.getString(Constants.EXTRAS_SHORTCODE)); }
break; else if (tappableObject.optString("__typename").equals("GraphTappableStoryPoll")) {
Log.d("austin_debug", "poll: "+url+" "+tappableObject);
models[i].setPoll(new PollModel(
tappableObject.getString("id"),
tappableObject.getString("question"),
tappableObject.getJSONArray("tallies").getJSONObject(0).getString("text"),
tappableObject.getJSONArray("tallies").getJSONObject(0).getInt("count"),
tappableObject.getJSONArray("tallies").getJSONObject(1).getString("text"),
tappableObject.getJSONArray("tallies").getJSONObject(1).getInt("count"),
tappableObject.optInt("viewer_vote", -1)
));
} }
} }
} }

View File

@ -0,0 +1,52 @@
package awais.instagrabber.models;
import java.io.Serializable;
public final class PollModel implements Serializable {
private int leftcount, rightcount, mychoice;
private final String id, question, leftchoice, rightchoice;
public PollModel(final String id, final String question, final String leftchoice, final int leftcount,
final String rightchoice, final int rightcount, final int mychoice) {
this.id = id; // only the poll id
this.question = question;
this.leftchoice = leftchoice;
this.leftcount = leftcount;
this.rightchoice = rightchoice;
this.rightcount = rightcount;
this.mychoice = mychoice;
}
public String getId() {
return id;
}
public String getQuestion() {
return question;
}
public String getLeftChoice() {
return leftchoice;
}
public int getLeftCount() {
return leftcount;
}
public String getRightChoice() {
return rightchoice;
}
public int getRightCount() {
return rightcount;
}
public int getMyChoice() { return mychoice; }
public int setMyChoice(final int choice) {
this.mychoice = choice;
if (choice == 0) this.leftcount += 1;
else if (choice == 1) this.rightcount += 1;
return choice;
}
}

View File

@ -9,6 +9,7 @@ public final class StoryModel implements Serializable {
private final MediaItemType itemType; private final MediaItemType itemType;
private final long timestamp; private final long timestamp;
private String videoUrl, tappableShortCode; private String videoUrl, tappableShortCode;
private PollModel poll;
private int position; private int position;
private boolean isCurrentSlide = false; private boolean isCurrentSlide = false;
@ -44,6 +45,10 @@ public final class StoryModel implements Serializable {
return tappableShortCode; return tappableShortCode;
} }
public PollModel getPoll() {
return poll;
}
public int getPosition() { public int getPosition() {
return position; return position;
} }
@ -56,6 +61,10 @@ public final class StoryModel implements Serializable {
this.tappableShortCode = tappableShortCode; this.tappableShortCode = tappableShortCode;
} }
public void setPoll(final PollModel poll) {
this.poll = poll;
}
public void setPosition(final int position) { public void setPosition(final int position) {
this.position = position; this.position = position;
} }

View File

@ -70,6 +70,7 @@ import awais.instagrabber.models.BasePostModel;
import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.FeedStoryModel;
import awais.instagrabber.models.HighlightModel; import awais.instagrabber.models.HighlightModel;
import awais.instagrabber.models.IntentModel; import awais.instagrabber.models.IntentModel;
import awais.instagrabber.models.PollModel;
import awais.instagrabber.models.ProfileModel; import awais.instagrabber.models.ProfileModel;
import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.StoryModel;
import awais.instagrabber.models.direct_messages.DirectItemModel; import awais.instagrabber.models.direct_messages.DirectItemModel;
@ -972,17 +973,17 @@ public final class Utils {
} }
public static void checkExistence(final File downloadDir, final File customDir, final String username, final boolean isSlider, public static void checkExistence(final File downloadDir, final File customDir, final String username, final boolean isSlider,
final int sliderIndex, @NonNull final BasePostModel model) { @NonNull final BasePostModel model) {
boolean exists = false; boolean exists = false;
try { try {
final String displayUrl = model.getDisplayUrl(); final String displayUrl = model.getDisplayUrl();
final int index = displayUrl.indexOf('?'); final int index = displayUrl.indexOf('?');
final String fileName = model.getPostId() + '_' + model.getPosition(); final String fileName = model.getPostId() + '_';
final String extension = displayUrl.substring(index - 4, index); final String extension = displayUrl.substring(index - 4, index);
final String fileWithoutPrefix = fileName + extension; final String fileWithoutPrefix = fileName + '0' + extension;
exists = new File(downloadDir, fileWithoutPrefix).exists(); exists = new File(downloadDir, fileWithoutPrefix).exists();
if (!exists) { if (!exists) {
if (customDir != null) exists = new File(customDir, fileWithoutPrefix).exists(); if (customDir != null) exists = new File(customDir, fileWithoutPrefix).exists();
@ -993,8 +994,8 @@ public final class Utils {
exists = new File(new File(customDir, username), fileWithoutPrefix).exists(); exists = new File(new File(customDir, username), fileWithoutPrefix).exists();
} }
if (!exists && isSlider && sliderIndex != -1) { if (!exists && isSlider) {
final String fileWithPrefix = fileName + "_slide_[\\d]+" + extension; final String fileWithPrefix = fileName + "[\\d]+_slide_[\\d]+" + extension;
final FilenameFilter filenameFilter = (dir, name) -> Pattern.matches(fileWithPrefix, name); final FilenameFilter filenameFilter = (dir, name) -> Pattern.matches(fileWithPrefix, name);
File[] files = downloadDir.listFiles(filenameFilter); File[] files = downloadDir.listFiles(filenameFilter);
@ -1007,7 +1008,6 @@ public final class Utils {
if (logCollector != null) if (logCollector != null)
logCollector.appendException(e, LogCollector.LogFile.UTILS, "checkExistence", logCollector.appendException(e, LogCollector.LogFile.UTILS, "checkExistence",
new Pair<>("isSlider", isSlider), new Pair<>("isSlider", isSlider),
new Pair<>("sliderIndex", sliderIndex),
new Pair<>("model", model)); new Pair<>("model", model));
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
} }
@ -1167,9 +1167,18 @@ public final class Utils {
for (int k = 0; k < tappableLength; ++k) { for (int k = 0; k < tappableLength; ++k) {
JSONObject jsonObject = tappableObjects.getJSONObject(k); JSONObject jsonObject = tappableObjects.getJSONObject(k);
if (jsonObject.getString("__typename").equals("GraphTappableFeedMedia") && jsonObject.has("media")) { if (jsonObject.getString("__typename").equals("GraphTappableFeedMedia") && jsonObject.has("media")) {
jsonObject = jsonObject.getJSONObject("media"); storyModels[j].setTappableShortCode(jsonObject.getJSONObject("media").getString(Constants.EXTRAS_SHORTCODE));
storyModels[j].setTappableShortCode(jsonObject.getString(Constants.EXTRAS_SHORTCODE)); }
break; else if (jsonObject.optString("__typename").equals("GraphTappableStoryPoll")) {
storyModels[j].setPoll(new PollModel(
jsonObject.getString("id"),
jsonObject.getString("question"),
jsonObject.getJSONArray("tallies").getJSONObject(0).getString("text"),
jsonObject.getJSONArray("tallies").getJSONObject(0).getInt("count"),
jsonObject.getJSONArray("tallies").getJSONObject(1).getString("text"),
jsonObject.getJSONArray("tallies").getJSONObject(1).getInt("count"),
jsonObject.optInt("viewer_vote", -1)
));
} }
} }
} }

View File

@ -38,15 +38,33 @@
android:layout_gravity="center" android:layout_gravity="center"
android:visibility="gone" /> android:visibility="gone" />
<androidx.appcompat.widget.AppCompatButton <androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/viewStoryPost" android:id="@+id/postActions"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_weight="0.3"
android:text="@string/view_story_post" android:background="#0000"
android:textColor="@color/btn_green_text_color" android:weightSum="2"
android:visibility="gone" android:layout_gravity="bottom">
app:backgroundTint="@color/btn_green_background" /> <androidx.appcompat.widget.AppCompatButton
android:id="@+id/viewStoryPost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/view_story_post"
android:textColor="@color/btn_green_text_color"
android:visibility="gone"
app:backgroundTint="@color/btn_green_background" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/interactStory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/view_story_post"
android:textColor="@color/btn_blue_text_color"
android:visibility="gone"
app:backgroundTint="@color/btn_blue_background" />
</androidx.appcompat.widget.LinearLayoutCompat>
</FrameLayout> </FrameLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View File

@ -60,6 +60,9 @@
<string name="show_stories">Show stories</string> <string name="show_stories">Show stories</string>
<string name="no_more_stories">No more stories!</string> <string name="no_more_stories">No more stories!</string>
<string name="view_story_post">View Story Post</string> <string name="view_story_post">View Story Post</string>
<string name="vote_story_poll">Vote</string>
<string name="votef_story_poll">Vote successful!</string>
<string name="voted_story_poll">You have already voted!</string>
<string name="priv_acc">This Account is Private</string> <string name="priv_acc">This Account is Private</string>
<string name="empty_acc">This Account has No Posts</string> <string name="empty_acc">This Account has No Posts</string>
<string name="curr_version">Current version: v%s</string> <string name="curr_version">Current version: v%s</string>