1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-12-22 21:16:57 +00:00

address #74, fix #76, fix #90, fix #104, fix #106

This commit is contained in:
Austin Huang 2020-09-01 13:37:00 -04:00
parent a6c912c5d5
commit c87311a68e
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
30 changed files with 392 additions and 120 deletions

View File

@ -1234,7 +1234,17 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
main.locationModel != null ? main.locationModel.getName() : main.userQuery.replaceAll("^@", "")));
onRefresh();
} else if (v == main.mainBinding.profileView.btnFollow) {
new ProfileAction().execute("follow");
if (main.profileModel.isPrivate()) {
new AlertDialog.Builder(main)
.setTitle(R.string.priv_acc)
.setMessage(R.string.priv_acc_confirm)
.setNegativeButton(R.string.no, null)
.setPositiveButton(R.string.yes, (dialog, which) -> new ProfileAction().execute("follow"))
.show();
}
else {
new ProfileAction().execute("follow");
}
} else if (v == main.mainBinding.profileView.btnRestrict && isLoggedIn) {
new ProfileAction().execute("restrict");
} else if (v == main.mainBinding.profileView.btnSaved && !iamme) {

View File

@ -18,11 +18,13 @@ import androidx.navigation.ui.NavigationUI;
import awais.instagrabber.R;
import awais.instagrabber.databinding.ActivityDirectMessagesBinding;
import awais.instagrabber.fragments.directmessages.DirectMessageThreadFragmentArgs;
import awais.instagrabber.utils.Constants;
import static awais.instagrabber.utils.Utils.settingsHelper;
public class DirectMessagesActivity extends BaseLanguageActivity implements NavController.OnDestinationChangedListener {
private TextView toolbarTitle;
private AppCompatImageView infoButton;
private AppCompatImageView dmInfo, dmSeen;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -36,7 +38,8 @@ public class DirectMessagesActivity extends BaseLanguageActivity implements NavC
final Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
infoButton = binding.dmInfo;
dmInfo = binding.dmInfo;
dmSeen = binding.dmSeen;
final NavController navController = Navigation.findNavController(this, R.id.direct_messages_nav_host_fragment);
navController.addOnDestinationChangedListener(this);
@ -51,7 +54,8 @@ public class DirectMessagesActivity extends BaseLanguageActivity implements NavC
switch (destination.getId()) {
case R.id.directMessagesInboxFragment:
setToolbarTitle(R.string.action_dms);
infoButton.setVisibility(View.GONE);
dmInfo.setVisibility(View.GONE);
dmSeen.setVisibility(View.GONE);
return;
case R.id.directMessagesThreadFragment:
if (arguments == null) {
@ -59,14 +63,16 @@ public class DirectMessagesActivity extends BaseLanguageActivity implements NavC
}
final String title = DirectMessageThreadFragmentArgs.fromBundle(arguments).getTitle();
setToolbarTitle(title);
infoButton.setVisibility(View.VISIBLE);
dmInfo.setVisibility(View.VISIBLE);
dmSeen.setVisibility(settingsHelper.getBoolean(Constants.DM_MARK_AS_SEEN) ? View.GONE : View.VISIBLE);
return;
case R.id.directMessagesSettingsFragment:
if (arguments == null) {
return;
}
setToolbarTitle(R.string.action_settings);
infoButton.setVisibility(View.GONE);
dmInfo.setVisibility(View.GONE);
dmSeen.setVisibility(View.GONE);
return;
}
}

View File

@ -127,7 +127,7 @@ public final class Main extends BaseLanguageActivity {
mainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mainBinding.getRoot());
FlavorTown.updateCheck(this);
if (settingsHelper.getBoolean(Constants.CHECK_UPDATES)) FlavorTown.updateCheck(this);
FlavorTown.changelogCheck(this);
cookie = settingsHelper.getString(Constants.COOKIE);

View File

@ -652,19 +652,12 @@ public final class PostViewer extends BaseLanguageActivity {
postUserId = result.getId();
final boolean hdPicEmpty = Utils.isEmpty(hdProfilePic);
glideRequestManager.load(hdPicEmpty ? sdProfilePic : hdProfilePic).listener(new RequestListener<Drawable>() {
private boolean loaded = true;
RequestListener<Drawable> profilePicListener = new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable final GlideException e, final Object model, final Target<Drawable> target, final boolean isFirstResource) {
viewerBinding.topPanel.ivProfilePic.setEnabled(false);
viewerBinding.topPanel.ivProfilePic.setOnClickListener(null);
if (loaded) {
loaded = false;
if (!Utils.isEmpty(sdProfilePic)) glideRequestManager.load(sdProfilePic).listener(this)
.into(viewerBinding.topPanel.ivProfilePic);
}
return false;
return true;
}
@Override
@ -673,7 +666,9 @@ public final class PostViewer extends BaseLanguageActivity {
viewerBinding.topPanel.ivProfilePic.setOnClickListener(onClickListener);
return false;
}
}).into(viewerBinding.topPanel.ivProfilePic);
};
glideRequestManager.load(hdPicEmpty ? sdProfilePic : hdProfilePic).listener(profilePicListener)
.error(glideRequestManager.load(sdProfilePic).listener(profilePicListener)).into(viewerBinding.topPanel.ivProfilePic);
final View viewStoryPost = findViewById(R.id.viewStoryPost);
if (viewStoryPost != null) {

View File

@ -103,9 +103,6 @@ public final class ProfilePicViewer extends BaseLanguageActivity {
errorHandled = true;
new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null))
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
glideRequestManager.load(profilePicUrl).into(profileBinding.imageViewer);
showImageInfo();
}
profileBinding.progressView.setVisibility(View.GONE);
return false;
@ -153,7 +150,7 @@ public final class ProfilePicViewer extends BaseLanguageActivity {
profileBinding.imageInfo.setVisibility(View.VISIBLE);
}
}
}).into(profileBinding.imageViewer);
}).error(glideRequestManager.load(profilePicUrl)).into(profileBinding.imageViewer);
};
new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null))

View File

@ -10,17 +10,22 @@ import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
import awais.instagrabber.R;
import awais.instagrabber.adapters.viewholder.FollowsViewHolder;
import awais.instagrabber.models.ProfileModel;
public final class DirectMessageMembersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final ProfileModel[] profileModels;
private final List<Long> admins;
private final View.OnClickListener onClickListener;
private final LayoutInflater layoutInflater;
public DirectMessageMembersAdapter(final ProfileModel[] profileModels, final Context context, final View.OnClickListener onClickListener) {
public DirectMessageMembersAdapter(final ProfileModel[] profileModels, final List<Long> admins,
final Context context, final View.OnClickListener onClickListener) {
this.profileModels = profileModels;
this.admins = admins;
this.layoutInflater = LayoutInflater.from(context);
this.onClickListener = onClickListener;
}
@ -44,6 +49,9 @@ public final class DirectMessageMembersAdapter extends RecyclerView.Adapter<Recy
followHolder.tvUsername.setText(model.getUsername());
followHolder.tvFullName.setText(model.getName());
if (admins != null && admins.contains(Long.parseLong(model.getId())))
followHolder.isAdmin.setVisibility(View.VISIBLE);
Glide.with(layoutInflater.getContext()).load(model.getSdProfilePic()).into(followHolder.profileImage);
}
}

View File

@ -104,5 +104,6 @@ public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHol
}
binding.tvComment.setText(HtmlCompat.fromHtml(messageText.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT));
binding.tvDate.setText(lastItemModel.getDateTime());
binding.unread.setVisibility(model.getUnreadCount() > 0L ? View.VISIBLE : View.GONE);
}
}

View File

@ -10,7 +10,7 @@ import androidx.recyclerview.widget.RecyclerView;
import awais.instagrabber.R;
public final class FollowsViewHolder extends RecyclerView.ViewHolder {
public final ImageView profileImage;
public final ImageView profileImage, isAdmin;
public final TextView tvFullName, tvUsername;
public FollowsViewHolder(@NonNull final View itemView) {
@ -18,5 +18,6 @@ public final class FollowsViewHolder extends RecyclerView.ViewHolder {
profileImage = itemView.findViewById(R.id.ivProfilePic);
tvFullName = itemView.findViewById(R.id.tvFullName);
tvUsername = itemView.findViewById(R.id.tvUsername);
isAdmin = itemView.findViewById(R.id.isAdmin);
}
}

View File

@ -56,7 +56,7 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
final String url;
if (isHashTag)
url = "https://www.instagram.com/graphql/query/?query_hash=ded47faa9a1aaded10161a2ff32abb6b&variables=" +
url = "https://www.instagram.com/graphql/query/?query_hash=9b498c08113f1e09617a1703c22b2f32&variables=" +
"{\"tag_name\":\"" + id.substring(1).toLowerCase() + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
else if (isLocation)
url = "https://www.instagram.com/graphql/query/?query_hash=36bd0f2bf5911908de389b8ceaa3be6d&variables=" +

View File

@ -86,6 +86,7 @@ public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> {
}
}
}
if (Utils.isEmpty(out)) out = picUrl;
} catch (final Exception e) {
if (logCollector != null)
logCollector.appendException(e, LogCollector.LogFile.ASYNC_PROFILE_PICTURE_FETCHER, "doInBackground");

View File

@ -161,7 +161,7 @@ public class DirectThreadBroadcaster extends AsyncTask<DirectThreadBroadcaster.B
super(ItemType.TEXT);
this.text = URLEncoder.encode(text, "UTF-8")
.replaceAll("\\+", "%20").replaceAll("%21", "!").replaceAll("%27", "'")
.replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~");
.replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~").replaceAll("%0A", "\n");
}
@Override
@ -197,7 +197,7 @@ public class DirectThreadBroadcaster extends AsyncTask<DirectThreadBroadcaster.B
super(ItemType.REELSHARE);
this.text = URLEncoder.encode(text, "UTF-8")
.replaceAll("\\+", "%20").replaceAll("%21", "!").replaceAll("%27", "'")
.replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~");
.replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~").replaceAll("%0A", "\n");
this.mediaId = mediaId;
this.reelId = reelId; // or user id, usually same
}

View File

@ -40,7 +40,9 @@ import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS;
import static awais.instagrabber.utils.Constants.AUTOPLAY_VIDEOS;
import static awais.instagrabber.utils.Constants.BOTTOM_TOOLBAR;
import static awais.instagrabber.utils.Constants.CHECK_ACTIVITY;
import static awais.instagrabber.utils.Constants.CHECK_UPDATES;
import static awais.instagrabber.utils.Constants.COOKIE;
import static awais.instagrabber.utils.Constants.DM_MARK_AS_SEEN;
import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER;
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
@ -133,22 +135,26 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V
final AppCompatCheckBox cbAutoplayVideos = contentView.findViewById(R.id.cbAutoplayVideos);
final AppCompatCheckBox cbDownloadUsername = contentView.findViewById(R.id.cbDownloadUsername);
final AppCompatCheckBox cbMarkAsSeen = contentView.findViewById(R.id.cbMarkAsSeen);
final AppCompatCheckBox cbMarkDmAsSeen = contentView.findViewById(R.id.cbMarkDmAsSeen);
final AppCompatCheckBox cbActivity = contentView.findViewById(R.id.cbActivity);
final AppCompatCheckBox cbInstadp = contentView.findViewById(R.id.cbInstadp);
final AppCompatCheckBox cbStoriesig = contentView.findViewById(R.id.cbStoriesig);
final AppCompatCheckBox cbAmoledTheme = contentView.findViewById(R.id.cbAmoledTheme);
final AppCompatCheckBox cbUpdates = contentView.findViewById(R.id.cbUpdates);
cbSaveTo.setChecked(settingsHelper.getBoolean(FOLDER_SAVE_TO));
cbMuteVideos.setChecked(settingsHelper.getBoolean(MUTED_VIDEOS));
cbBottomToolbar.setChecked(settingsHelper.getBoolean(BOTTOM_TOOLBAR));
cbAutoplayVideos.setChecked(settingsHelper.getBoolean(AUTOPLAY_VIDEOS));
cbMarkAsSeen.setChecked(settingsHelper.getBoolean(MARK_AS_SEEN));
cbMarkDmAsSeen.setChecked(settingsHelper.getBoolean(DM_MARK_AS_SEEN));
cbInstadp.setChecked(settingsHelper.getBoolean(INSTADP));
cbStoriesig.setChecked(settingsHelper.getBoolean(STORIESIG));
cbAmoledTheme.setChecked(settingsHelper.getBoolean(AMOLED_THEME));
cbActivity.setChecked(settingsHelper.getBoolean(CHECK_ACTIVITY));
cbAutoloadPosts.setChecked(settingsHelper.getBoolean(AUTOLOAD_POSTS));
cbDownloadUsername.setChecked(settingsHelper.getBoolean(DOWNLOAD_USER_FOLDER));
cbUpdates.setChecked(settingsHelper.getBoolean(CHECK_UPDATES));
setupListener(cbSaveTo);
setupListener(cbMuteVideos);
@ -157,10 +163,12 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V
setupListener(cbAutoplayVideos);
setupListener(cbDownloadUsername);
setupListener(cbMarkAsSeen);
setupListener(cbMarkDmAsSeen);
setupListener(cbInstadp);
setupListener(cbStoriesig);
setupListener(cbAmoledTheme);
setupListener(cbActivity);
setupListener(cbUpdates);
btnSaveTo.setEnabled(cbSaveTo.isChecked());
@ -229,10 +237,12 @@ public final class SettingsDialog extends BottomSheetDialogFragment implements V
else if (id == R.id.cbMuteVideos) settingsHelper.putBoolean(MUTED_VIDEOS, checked);
else if (id == R.id.cbAutoloadPosts) settingsHelper.putBoolean(AUTOLOAD_POSTS, checked);
else if (id == R.id.cbMarkAsSeen) settingsHelper.putBoolean(MARK_AS_SEEN, checked);
else if (id == R.id.cbMarkDmAsSeen) settingsHelper.putBoolean(DM_MARK_AS_SEEN, checked);
else if (id == R.id.cbInstadp) settingsHelper.putBoolean(INSTADP, checked);
else if (id == R.id.cbStoriesig) settingsHelper.putBoolean(STORIESIG, checked);
else if (id == R.id.cbAmoledTheme) settingsHelper.putBoolean(AMOLED_THEME, checked);
else if (id == R.id.cbActivity) settingsHelper.putBoolean(CHECK_ACTIVITY, checked);
else if (id == R.id.cbUpdates) settingsHelper.putBoolean(CHECK_UPDATES, checked);
else if (id == R.id.cbSaveTo) {
settingsHelper.putBoolean(FOLDER_SAVE_TO, checked);
btnSaveTo.setEnabled(checked);

View File

@ -9,6 +9,7 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;
@ -29,6 +30,8 @@ import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.R;
@ -46,16 +49,18 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
private static final String TAG = "DirectMessagesSettingsFrag";
private FragmentActivity fragmentActivity;
private RecyclerView userList;
private RecyclerView userList, leftUserList;
private EditText titleText;
private View leftTitle;
private AppCompatImageView titleSend;
private AppCompatButton btnLeave;
private LinearLayoutManager layoutManager;
private LinearLayoutManager layoutManager, layoutManagerDos;
private String threadId, threadTitle;
private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
private boolean amAdmin;
private AsyncTask<Void, Void, InboxThreadModel> currentlyRunning;
private DirectMessageMembersAdapter memberAdapter;
private View.OnClickListener clickListener;
private DirectMessageMembersAdapter memberAdapter, leftAdapter;
private View.OnClickListener clickListener, basicClickListener;
private final FetchListener<InboxThreadModel> fetchListener = new FetchListener<InboxThreadModel>() {
@Override
@ -63,8 +68,15 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
@Override
public void onResult(final InboxThreadModel threadModel) {
memberAdapter = new DirectMessageMembersAdapter(threadModel.getUsers(), requireContext(), clickListener);
final List<Long> adminList = Arrays.asList(threadModel.getAdmins());
amAdmin = adminList.contains(Long.parseLong(Utils.getUserIdFromCookie(cookie)));
memberAdapter = new DirectMessageMembersAdapter(threadModel.getUsers(), adminList, requireContext(), amAdmin ? clickListener : basicClickListener);
userList.setAdapter(memberAdapter);
if (threadModel.getLeftUsers() != null && threadModel.getLeftUsers().length > 0) {
leftTitle.setVisibility(View.VISIBLE);
leftAdapter = new DirectMessageMembersAdapter(threadModel.getLeftUsers(), null, requireContext(), basicClickListener);
leftUserList.setAdapter(leftAdapter);
}
}
};
@ -73,10 +85,9 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
super.onCreate(savedInstanceState);
fragmentActivity = requireActivity();
clickListener = v -> {
basicClickListener = v -> {
final Object tag = v.getTag();
if (tag instanceof ProfileModel) {
// TODO: kick dialog
ProfileModel model = (ProfileModel) tag;
startActivity(
new Intent(requireContext(), ProfileViewer.class)
@ -84,6 +95,37 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
);
}
};
clickListener = v -> {
final Object tag = v.getTag();
if (tag instanceof ProfileModel) {
ProfileModel model = (ProfileModel) tag;
if (!amAdmin || model.getId().equals(Utils.getUserIdFromCookie(cookie))) {
startActivity(
new Intent(requireContext(), ProfileViewer.class)
.putExtra(Constants.EXTRAS_USERNAME, model.getUsername())
);
}
else {
new AlertDialog.Builder(requireContext()).setAdapter(
new ArrayAdapter<>(requireContext(), android.R.layout.simple_list_item_1, new String[]{
getString(R.string.open_profile),
getString(R.string.dms_action_kick),
}),
(d,w) -> {
if (w == 0)
startActivity(
new Intent(requireContext(), ProfileViewer.class)
.putExtra(Constants.EXTRAS_USERNAME, model.getUsername())
);
else if (w == 1) {
new ChangeSettings().execute("remove_users", model.getId());
onRefresh();
}
}).show();
}
}
};
}
@Override
@ -92,7 +134,18 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
final Bundle savedInstanceState) {
final FragmentDirectMessagesSettingsBinding binding = FragmentDirectMessagesSettingsBinding.inflate(inflater, container, false);
final LinearLayout root = binding.getRoot();
layoutManager = new LinearLayoutManager(requireContext());
layoutManager = new LinearLayoutManager(requireContext()) {
@Override
public boolean canScrollVertically() {
return false;
}
};
layoutManagerDos = new LinearLayoutManager(requireContext()) {
@Override
public boolean canScrollVertically() {
return false;
}
};
threadId = DirectMessageSettingsFragmentArgs.fromBundle(getArguments()).getThreadId();
threadTitle = DirectMessageSettingsFragmentArgs.fromBundle(getArguments()).getTitle();
@ -102,6 +155,12 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
userList.setHasFixedSize(true);
userList.setLayoutManager(layoutManager);
leftUserList = binding.leftUserList;
leftUserList.setHasFixedSize(true);
leftUserList.setLayoutManager(layoutManagerDos);
leftTitle = binding.leftTitle;
titleText = binding.titleText;
titleText.setText(threadTitle);
@ -154,11 +213,12 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
}
class ChangeSettings extends AsyncTask<String, Void, Void> {
String action;
String action, argument;
boolean ok = false;
protected Void doInBackground(String... rawAction) {
action = rawAction[0];
if (rawAction.length == 2) argument = rawAction[1];
final String url = "https://i.instagram.com/api/v1/direct_v2/threads/"+threadId+"/"+action+"/";
try {
String urlParameters = "_csrftoken=" + cookie.split("csrftoken=")[1].split(";")[0]
@ -167,6 +227,8 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
urlParameters += "&title=" + URLEncoder.encode(titleText.getText().toString(), "UTF-8")
.replaceAll("\\+", "%20").replaceAll("%21", "!").replaceAll("%27", "'")
.replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~");
else if (action.startsWith("remove_users"))
urlParameters += ("&user_ids=[" + argument + "]");
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
@ -197,11 +259,15 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
threadTitle = titleText.getText().toString();
titleSend.setVisibility(View.GONE);
titleText.clearFocus();
DirectMessageThreadFragment.hasSentSomething = true;
}
else if (action.equals("leave")) {
DirectMessageInboxFragment.refreshPlease = true;
NavHostFragment.findNavController(DirectMessageSettingsFragment.this).popBackStack(R.id.directMessagesInboxFragment, false);
}
else {
DirectMessageThreadFragment.hasSentSomething = true;
}
}
else Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}

View File

@ -77,17 +77,17 @@ public class DirectMessageThreadFragment extends Fragment {
private static final int PICK_IMAGE = 100;
private FragmentActivity fragmentActivity;
private String threadId, threadTitle;
private String cursor;
private String threadId, threadTitle, cursor, lastMessage;
private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
private final String myId = Utils.getUserIdFromCookie(cookie);
private FragmentDirectMessagesThreadBinding binding;
private DirectItemModelListViewModel listViewModel;
private DirectItemModel directItemModel;
private RecyclerView messageList;
private AppCompatImageView dmInfo;
private boolean hasSentSomething, hasDeletedSomething;
private AppCompatImageView dmInfo, dmSeen;
private boolean hasDeletedSomething;
private boolean hasOlder = true;
public static boolean hasSentSomething;
private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel();
private final List<ProfileModel> users = new ArrayList<>();
@ -151,6 +151,10 @@ public class DirectMessageThreadFragment extends Fragment {
list.addAll(newList);
}
listViewModel.getList().postValue(list);
lastMessage = result.getNewestCursor();
if (Utils.settingsHelper.getBoolean(Constants.DM_MARK_AS_SEEN)) new ThreadAction().execute("seen", lastMessage);
}
binding.swipeRefreshLayout.setRefreshing(false);
}
@ -162,6 +166,14 @@ public class DirectMessageThreadFragment extends Fragment {
fragmentActivity = requireActivity();
}
@Override
public void onResume() {
super.onResume();
if (hasSentSomething) {
new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
final ViewGroup container,
@ -169,6 +181,7 @@ public class DirectMessageThreadFragment extends Fragment {
binding = FragmentDirectMessagesThreadBinding.inflate(inflater, container, false);
CoordinatorLayout containerTwo = (CoordinatorLayout) container.getParent();
dmInfo = containerTwo.findViewById(R.id.dmInfo);
dmSeen = containerTwo.findViewById(R.id.dmSeen);
final LinearLayout root = binding.getRoot();
listViewModel = new ViewModelProvider(fragmentActivity).get(DirectItemModelListViewModel.class);
if (getArguments() == null) {
@ -200,6 +213,11 @@ public class DirectMessageThreadFragment extends Fragment {
NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(action);
});
dmSeen.setOnClickListener(v -> {
new ThreadAction().execute("seen", lastMessage);
dmSeen.setVisibility(View.GONE);
});
final DialogInterface.OnClickListener onDialogListener = (dialogInterface, which) -> {
if (which == 0) {
final DirectItemType itemType = directItemModel.getItemType();
@ -266,7 +284,7 @@ public class DirectMessageThreadFragment extends Fragment {
sendText(null, directItemModel.getItemId(), directItemModel.isLiked());
}
else if (which == 2) {
if (String.valueOf(directItemModel.getUserId()).equals(myId)) new Unsend().execute();
if (String.valueOf(directItemModel.getUserId()).equals(myId)) new ThreadAction().execute("delete", directItemModel.getItemId());
else searchUsername(getUser(directItemModel.getUserId()).getUsername());
}
};
@ -462,9 +480,13 @@ public class DirectMessageThreadFragment extends Fragment {
}
}
class Unsend extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... lmao) {
final String url = "https://i.instagram.com/api/v1/direct_v2/threads/"+threadId+"/items/"+directItemModel.getItemId()+"/delete/";
class ThreadAction extends AsyncTask<String, Void, Void> {
String action, argument;
protected Void doInBackground(String... rawAction) {
action = rawAction[0];
argument = rawAction[1];
final String url = "https://i.instagram.com/api/v1/direct_v2/threads/"+threadId+"/items/"+argument+"/"+action+"/";
try {
String urlParameters = "_csrftoken=" + cookie.split("csrftoken=")[1].split(";")[0]
+"&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID);
@ -481,11 +503,12 @@ public class DirectMessageThreadFragment extends Fragment {
wr.close();
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
hasDeletedSomething = true;
if (action == "delete") hasDeletedSomething = true;
else if (action == "seen") DirectMessageInboxFragment.refreshPlease = true;
}
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "unsend: " + ex);
Log.e("austin_debug", action + ": " + ex);
}
return null;
}

View File

@ -12,16 +12,17 @@ public final class InboxThreadModel implements Serializable {
private final String threadId, threadV2Id, threadType, threadTitle, newestCursor, oldestCursor, nextCursor, prevCursor;
private final ProfileModel inviter;
private final ProfileModel[] users, leftUsers;
private final Long[] admins;
private final DirectItemModel[] items;
private final boolean muted, isPin, isSpam, isGroup, named, pending, archived, canonical, hasOlder, hasNewer;
private final long lastActivityAt;
private final boolean muted, isPin, isSpam, isGroup, named, pending, archived, canonical, hasOlder;
private final long unreadCount, lastActivityAt;
public InboxThreadModel(final InboxReadState readState, final String threadId, final String threadV2Id, final String threadType, final String threadTitle,
final String newestCursor, final String oldestCursor, final String nextCursor, final String prevCursor,
final ProfileModel inviter, final ProfileModel[] users,
final ProfileModel[] leftUsers, final DirectItemModel[] items, final boolean muted,
final ProfileModel inviter, final ProfileModel[] users, final ProfileModel[] leftUsers,
final Long[] admins, final DirectItemModel[] items, final boolean muted,
final boolean isPin, final boolean named, final boolean canonical, final boolean pending,
final boolean hasOlder, final boolean hasNewer, final boolean isSpam, final boolean isGroup,
final boolean hasOlder, final long unreadCount, final boolean isSpam, final boolean isGroup,
final boolean archived, final long lastActivityAt) {
this.readState = readState;
this.threadId = threadId;
@ -35,6 +36,7 @@ public final class InboxThreadModel implements Serializable {
this.inviter = inviter;
this.users = users;
this.leftUsers = leftUsers;
this.admins = admins;
this.items = items; // todo
this.muted = muted;
this.isPin = isPin;
@ -42,7 +44,7 @@ public final class InboxThreadModel implements Serializable {
this.canonical = canonical;
this.pending = pending;
this.hasOlder = hasOlder;
this.hasNewer = hasNewer;
this.unreadCount = unreadCount;
this.isSpam = isSpam;
this.isGroup = isGroup;
this.archived = archived;
@ -97,6 +99,8 @@ public final class InboxThreadModel implements Serializable {
return leftUsers;
}
public Long[] getAdmins() { return admins; }
public DirectItemModel[] getItems() {
return items;
}
@ -129,9 +133,7 @@ public final class InboxThreadModel implements Serializable {
return hasOlder;
}
public boolean isHasNewer() {
return hasNewer;
}
public long getUnreadCount() { return unreadCount; }
public boolean isSpam() {
return isSpam;

View File

@ -20,10 +20,12 @@ public final class Constants {
public static final String SHOW_FEED = "show_feed";
public static final String CUSTOM_DATE_TIME_FORMAT_ENABLED = "data_time_custom_enabled";
public static final String MARK_AS_SEEN = "mark_as_seen";
public static final String DM_MARK_AS_SEEN = "dm_mark_as_seen";
public static final String INSTADP = "instadp";
public static final String STORIESIG = "storiesig";
public static final String AMOLED_THEME = "amoled_theme";
public static final String CHECK_ACTIVITY = "check_activity";
public static final String CHECK_UPDATES = "check_updates";
// never Export
public static final String COOKIE = "cookie";
public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg";
@ -50,9 +52,9 @@ public final class Constants {
// spoof
public static final String USER_AGENT = "Mozilla/5.0 (Linux; Android 8.1.0; motorola one Build/OPKS28.63-18-3; wv) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36 " +
"Instagram 154.0.0.32.123 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 238093938)";
"Instagram 156.0.0.26.109 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 240726452)";
public static final String I_USER_AGENT =
"Instagram 154.0.0.32.123 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 238093938)";
"Instagram 156.0.0.26.109 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 240726452)";
public static final String A_USER_AGENT = "https://InstaGrabber.AustinHuang.me / mailto:InstaGrabber@AustinHuang.me";
// see https://github.com/dilame/instagram-private-api/blob/master/src/core/constants.ts
public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" +

View File

@ -15,12 +15,14 @@ import static awais.instagrabber.utils.Constants.AUTOLOAD_POSTS;
import static awais.instagrabber.utils.Constants.AUTOPLAY_VIDEOS;
import static awais.instagrabber.utils.Constants.BOTTOM_TOOLBAR;
import static awais.instagrabber.utils.Constants.CHECK_ACTIVITY;
import static awais.instagrabber.utils.Constants.CHECK_UPDATES;
import static awais.instagrabber.utils.Constants.COOKIE;
import static awais.instagrabber.utils.Constants.CUSTOM_DATE_TIME_FORMAT;
import static awais.instagrabber.utils.Constants.CUSTOM_DATE_TIME_FORMAT_ENABLED;
import static awais.instagrabber.utils.Constants.DATE_TIME_FORMAT;
import static awais.instagrabber.utils.Constants.DATE_TIME_SELECTION;
import static awais.instagrabber.utils.Constants.DEVICE_UUID;
import static awais.instagrabber.utils.Constants.DM_MARK_AS_SEEN;
import static awais.instagrabber.utils.Constants.DOWNLOAD_USER_FOLDER;
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
@ -76,7 +78,8 @@ public final class SettingsHelper {
return BOTTOM_TOOLBAR.equals(key) ||
AUTOPLAY_VIDEOS.equals(key) ||
SHOW_QUICK_ACCESS_DIALOG.equals(key) ||
MUTED_VIDEOS.equals(key);
MUTED_VIDEOS.equals(key) ||
CHECK_UPDATES.equals(key);
}
public int getThemeCode(final boolean fromHelper) {
@ -111,7 +114,8 @@ public final class SettingsHelper {
public @interface StringSettings {}
@StringDef({DOWNLOAD_USER_FOLDER, BOTTOM_TOOLBAR, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
AUTOLOAD_POSTS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, INSTADP, STORIESIG, AMOLED_THEME, CHECK_ACTIVITY})
AUTOLOAD_POSTS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN,
INSTADP, STORIESIG, AMOLED_THEME, CHECK_ACTIVITY, CHECK_UPDATES})
public @interface BooleanSettings {}
@StringDef({APP_THEME, APP_LANGUAGE, PREV_INSTALL_VERSION})

View File

@ -474,7 +474,7 @@ public final class Utils {
@NonNull
public static InboxThreadModel createInboxThreadModel(@NonNull final JSONObject data, final boolean inThreadView) throws Exception {
final InboxReadState readState = data.getInt("read_state") == 0 ? InboxReadState.STATE_READ : InboxReadState.STATE_UNREAD;
final String threadType = data.getString("thread_type");// private = dms, [??] = group
final String threadType = data.getString("thread_type"); // they're all "private", group is identified by boolean "is_group"
final String threadId = data.getString("thread_id");
final String threadV2Id = data.getString("thread_v2_id");
@ -486,7 +486,7 @@ public final class Utils {
final String threadPrevCursor = data.has("prev_cursor") ? data.getString("prev_cursor") : null;
final boolean threadHasOlder = data.getBoolean("has_older");
final boolean threadHasNewer = data.getBoolean("has_newer");
final long unreadCount = data.optLong("read_state", 0);
final long lastActivityAt = data.optLong("last_activity_at");
final boolean named = data.optBoolean("named");
@ -502,6 +502,8 @@ public final class Utils {
final int usersLen = users.length();
final JSONArray leftusers = data.getJSONArray("left_users");
final int leftusersLen = leftusers.length();
final JSONArray admins = data.getJSONArray("admin_user_ids");
final int adminsLen = admins.length();
final ProfileModel[] userModels = new ProfileModel[usersLen];
for (int j = 0; j < usersLen; ++j) {
@ -531,6 +533,11 @@ public final class Utils {
null, 0, 0, 0, false, false, false, false);
}
final Long[] adminIDs = new Long[adminsLen];
for (int j = 0; j < adminsLen; ++j) {
adminIDs[j] = admins.getLong(j);
}
final JSONArray items = data.getJSONArray("items");
final int itemsLen = items.length();
@ -707,7 +714,6 @@ public final class Utils {
break;
case CLIP:
Log.d("austin_debug", "clip: "+itemObject.getJSONObject("clip").getJSONObject("clip"));
directMedia = getDirectMediaModel(itemObject.getJSONObject("clip").getJSONObject("clip"));
break;
@ -776,10 +782,10 @@ public final class Utils {
return new InboxThreadModel(readState, threadId, threadV2Id, threadType, threadTitle,
threadNewestCursor, threadOldestCursor, threadNextCursor, threadPrevCursor,
null, // todo
userModels, leftuserModels,
userModels, leftuserModels, adminIDs,
itemModels.toArray(new DirectItemModel[0]),
muted, isPin, named, canonical,
pending, threadHasOlder, threadHasNewer, isSpam, isGroup, archived, lastActivityAt);
pending, threadHasOlder, unreadCount, isSpam, isGroup, archived, lastActivityAt);
}
private static RavenExpiringMediaType getExpiringMediaType(final String type) {

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="#ff0000"/>
<size
android:width="120dp"
android:height="120dp"/>
</shape>

View File

@ -49,6 +49,22 @@
android:gravity="center_vertical"
android:text="@string/app_name" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/dmSeen"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:paddingStart="4dp"
android:paddingLeft="4dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:paddingBottom="4dp"
app:srcCompat="@android:drawable/ic_menu_view" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/dmInfo"
android:layout_width="wrap_content"

View File

@ -46,6 +46,42 @@
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
android:weightSum="2">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:text="@string/login"
android:textColor="@color/btn_green_text_color"
android:textSize="20sp"
app:backgroundTint="@color/btn_green_background" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnLogout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:text="@string/logout"
android:textColor="@color/btn_red_text_color"
android:textSize="20sp"
app:backgroundTint="@color/btn_red_background" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -209,6 +245,31 @@
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
android:padding="5dp">
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cbUpdates"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/bottom_toolbar" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="5dp"
android:text="@string/update_check"
android:textColor="?android:textColorPrimary"
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -320,6 +381,31 @@
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
android:padding="5dp">
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cbMarkDmAsSeen"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/dm_mark_as_seen_setting" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="5dp"
android:text="@string/dm_mark_as_seen_setting"
android:textColor="?android:textColorPrimary"
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -419,42 +505,6 @@
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
android:weightSum="2">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:text="@string/login"
android:textColor="@color/btn_green_text_color"
android:textSize="20sp"
app:backgroundTint="@color/btn_green_background" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnLogout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:text="@string/logout"
android:textColor="@color/btn_red_text_color"
android:textSize="20sp"
app:backgroundTint="@color/btn_red_background" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnTimeSettings"
android:layout_width="match_parent"

View File

@ -60,9 +60,35 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/userList"
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/userList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/leftTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:gravity="center_vertical"
android:padding="5dp"
android:text="@string/dms_left_users"
android:textColor="?android:textColorPrimary"
android:textSize="24sp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/leftUserList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>

View File

@ -20,6 +20,7 @@
android:layout_height="60dp"
android:layout_marginStart="66dp"
android:layout_marginLeft="66dp"
android:layout_marginEnd="26dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
@ -41,4 +42,13 @@
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/isAdmin"
android:layout_width="20dp"
android:layout_height="60dp"
android:layout_gravity="right"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_star"
android:visibility="gone"/>
</FrameLayout>

View File

@ -51,22 +51,35 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvUsername"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_weight="1.0"
android:ellipsize="marquee"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingTop="4dp"
android:paddingEnd="4dp"
android:paddingRight="4dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:textColorPrimary"
android:textStyle="bold" />
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_weight="1.0"
android:ellipsize="marquee"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingTop="4dp"
android:paddingEnd="4dp"
android:paddingRight="4dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:textColorPrimary"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/unread"
android:layout_width="15dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:scaleType="fitCenter"
app:srcCompat="@drawable/circle"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
@ -101,8 +114,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="3">
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvLikes"
android:layout_width="0dp"
@ -127,8 +139,7 @@
android:paddingStart="4dp"
android:paddingLeft="4dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:paddingRight="4dp"
android:singleLine="true"
android:textStyle="italic"
android:gravity="right"/>

View File

@ -34,9 +34,11 @@
<string name="title_user_story">User Story</string>
<string name="title_changelog">Changelog</string>
<string name="bottom_toolbar">Show toolbar at bottom</string>
<string name="update_check">Check for new updates on GitHub at startup</string>
<string name="download_user_folder">Download posts to username folder in Downloads</string>
<string name="autoload_posts">Auto-load all posts from user</string>
<string name="mark_as_seen_setting">Mark stories as seen after viewing\n(Story author will know you viewed it)</string>
<string name="dm_mark_as_seen_setting">Automatically mark DM as seen after viewing\n(Other members will know you viewed it)</string>
<string name="activity_setting">Enable activity notifications</string>
<string name="error_loading_profile">Error loading profile!\nTry logging in and search again.</string>
<string name="error_creating_folders">Error creating Download folder(s).</string>
@ -84,6 +86,7 @@
<string name="story_quizzed">You have already answered!</string>
<string name="story_mentions">Mentions</string>
<string name="priv_acc">This Account is Private</string>
<string name="priv_acc_confirm">You won\'t be able to access posts after unfollowing! Are you sure?</string>
<string name="no_acc">You can log in via Settings on the bottom-right corner. Or, you can view public accounts without login!</string>
<string name="no_acc_logged_in">You can swipe left/right for explore/feed, or search something below!</string>
<string name="empty_acc">This Account has No Posts</string>
@ -173,6 +176,8 @@
<string name="dms_action_success">Great success!</string>
<string name="dms_action_leave">Leave</string>
<string name="dms_action_leave_question">Leave this chat?</string>
<string name="dms_action_kick">Kick</string>
<string name="dms_left_users">Left users</string>
<string name="direct_download">Download directly</string>
<string name="direct_download_desc">Downloads posts directly to the phone!</string>
<string name="direct_download_loading">Fetching post(s)</string>