mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-10-31 03:25:34 +00:00 
			
		
		
		
	notification viewer + hd avatar
This commit is contained in:
		
							parent
							
								
									ca8e2d58de
								
							
						
					
					
						commit
						8726a924a0
					
				| @ -186,6 +186,15 @@ | ||||
|                 android:value=".activities.Main" /> | ||||
|         </activity> | ||||
| 
 | ||||
|         <activity | ||||
|             android:name=".activities.NotificationsViewer" | ||||
|             android:parentActivityName=".activities.Main"> | ||||
| 
 | ||||
|             <meta-data | ||||
|                 android:name="android.support.PARENT_ACTIVITY" | ||||
|                 android:value=".activities.Main" /> | ||||
|         </activity> | ||||
| 
 | ||||
|         <activity | ||||
|             android:name=".activities.Login" | ||||
|             android:label="@string/login" | ||||
|  | ||||
| @ -87,7 +87,7 @@ public final class Main extends BaseLanguageActivity { | ||||
|     private MenuItem searchAction; | ||||
|     public ActivityMainBinding mainBinding; | ||||
|     public SearchView searchView; | ||||
|     public MenuItem downloadAction, settingsAction, dmsAction; | ||||
|     public MenuItem downloadAction, settingsAction, dmsAction, notifAction; | ||||
|     public StoryModel[] storyModels; | ||||
|     public String userQuery = null; | ||||
|     public MainHelper mainHelper; | ||||
| @ -118,9 +118,6 @@ public final class Main extends BaseLanguageActivity { | ||||
|         final String uid = Utils.getUserIdFromCookie(cookie); | ||||
|         Utils.setupCookies(cookie); | ||||
| 
 | ||||
|         if (settingsHelper.getInteger(Constants.PROFILE_FETCH_MODE) == 2) | ||||
|             settingsHelper.putInteger(Constants.PROFILE_FETCH_MODE, 1); | ||||
| 
 | ||||
|         MainHelper.stopCurrentExecutor(); | ||||
|         mainHelper = new MainHelper(this); | ||||
|         if (bundle == null) { | ||||
| @ -292,10 +289,12 @@ public final class Main extends BaseLanguageActivity { | ||||
|         final MenuItem quickAccessAction = menu.findItem(R.id.action_quickaccess).setVisible(true); | ||||
| 
 | ||||
|         final MenuItem.OnMenuItemClickListener clickListener = item -> { | ||||
|             if (item == downloadAction) { | ||||
|             if (item == downloadAction) | ||||
|                 downloadSelectedItems(); | ||||
|             } else if (item == dmsAction) | ||||
|             else if (item == dmsAction) | ||||
|                 startActivity(new Intent(this, DirectMessages.class)); | ||||
|             else if (item == notifAction) | ||||
|                 startActivity(new Intent(this, NotificationsViewer.class)); | ||||
|             else if (item == settingsAction) | ||||
|                 new SettingsDialog().show(fragmentManager, "settings"); | ||||
|             else if (item == quickAccessAction) | ||||
| @ -310,11 +309,12 @@ public final class Main extends BaseLanguageActivity { | ||||
|         quickAccessAction.setOnMenuItemClickListener(clickListener); | ||||
|         menu.findItem(R.id.action_about).setVisible(true).setOnMenuItemClickListener(clickListener); | ||||
|         dmsAction = menu.findItem(R.id.action_dms).setOnMenuItemClickListener(clickListener); | ||||
|         notifAction = menu.findItem(R.id.action_notif).setOnMenuItemClickListener(clickListener); | ||||
|         settingsAction = menu.findItem(R.id.action_settings).setVisible(true).setOnMenuItemClickListener(clickListener); | ||||
|         downloadAction = menu.findItem(R.id.action_download).setOnMenuItemClickListener(clickListener); | ||||
| 
 | ||||
|         if (!Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE))) { | ||||
|             //settingsAction.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); | ||||
|             notifAction.setVisible(true); | ||||
|             dmsAction.setVisible(true).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										140
									
								
								app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										140
									
								
								app/src/main/java/awais/instagrabber/activities/NotificationsViewer.java
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,140 @@ | ||||
| package awais.instagrabber.activities; | ||||
| 
 | ||||
| import android.content.DialogInterface; | ||||
| import android.content.Intent; | ||||
| import android.content.res.Resources; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Bundle; | ||||
| import android.text.SpannableString; | ||||
| import android.text.Spanned; | ||||
| import android.text.style.RelativeSizeSpan; | ||||
| import android.util.Log; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.inputmethod.InputMethodManager; | ||||
| import android.widget.ArrayAdapter; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.widget.SearchView; | ||||
| import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | ||||
| 
 | ||||
| import java.io.DataOutputStream; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| import java.net.URLEncoder; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.NotificationsAdapter; | ||||
| import awais.instagrabber.asyncs.NotificationsFetcher; | ||||
| import awais.instagrabber.databinding.ActivityNotificationBinding; | ||||
| import awais.instagrabber.interfaces.FetchListener; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.NotificationModel; | ||||
| import awais.instagrabber.models.PostModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class NotificationsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener { | ||||
|     private NotificationsAdapter notificationsAdapter; | ||||
|     private NotificationModel notificationModel; | ||||
|     private ActivityNotificationBinding notificationsBinding; | ||||
|     private ArrayAdapter<String> commmentDialogAdapter; | ||||
|     private String shortCode, postId, userId; | ||||
|     private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); | ||||
|     private Resources resources; | ||||
|     private InputMethodManager imm; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(@Nullable final Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         notificationsBinding = ActivityNotificationBinding.inflate(getLayoutInflater()); | ||||
|         setContentView(notificationsBinding.getRoot()); | ||||
|         notificationsBinding.swipeRefreshLayout.setOnRefreshListener(this); | ||||
| 
 | ||||
|         notificationsBinding.swipeRefreshLayout.setRefreshing(true); | ||||
|         setSupportActionBar(notificationsBinding.toolbar.toolbar); | ||||
|         notificationsBinding.toolbar.toolbar.setTitle(R.string.title_notifications); | ||||
| 
 | ||||
|         resources = getResources(); | ||||
| 
 | ||||
|         new NotificationsFetcher(new FetchListener<NotificationModel[]>() { | ||||
|             @Override | ||||
|             public void onResult(final NotificationModel[] notificationModels) { | ||||
|                 notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener); | ||||
| 
 | ||||
|                 notificationsBinding.rvComments.setAdapter(notificationsAdapter); | ||||
|                 notificationsBinding.swipeRefreshLayout.setRefreshing(false); | ||||
|             } | ||||
|         }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRefresh() { | ||||
|         notificationsBinding.swipeRefreshLayout.setRefreshing(true); | ||||
|         new NotificationsFetcher(new FetchListener<NotificationModel[]>() { | ||||
|             @Override | ||||
|             public void onResult(final NotificationModel[] notificationModels) { | ||||
|                 notificationsBinding.swipeRefreshLayout.setRefreshing(false); | ||||
| 
 | ||||
|                 notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener); | ||||
| 
 | ||||
|                 notificationsBinding.rvComments.setAdapter(notificationsAdapter); | ||||
|             } | ||||
|         }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|     } | ||||
| 
 | ||||
|     final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> { | ||||
|         if (which == 0) | ||||
|             searchUsername(notificationModel.getUsername()); | ||||
|         else if (which == 1) | ||||
|             startActivity(new Intent(getApplicationContext(), PostViewer.class) | ||||
|                     .putExtra(Constants.EXTRAS_POST, new PostModel(notificationModel.getShortcode()))); | ||||
|     }; | ||||
| 
 | ||||
|     private final View.OnClickListener clickListener = v -> { | ||||
|         final Object tag = v.getTag(); | ||||
|         if (tag instanceof NotificationModel) { | ||||
|             notificationModel = (NotificationModel) tag; | ||||
| 
 | ||||
|             final String username = notificationModel.getUsername(); | ||||
|             final SpannableString title = new SpannableString(username + ":\n" + notificationModel.getText()); | ||||
|             title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); | ||||
| 
 | ||||
|             String[] commentDialogList; | ||||
| 
 | ||||
|             if (notificationModel.getShortcode() != null) commentDialogList = new String[]{ | ||||
|                     resources.getString(R.string.open_profile), | ||||
|                     resources.getString(R.string.view_post) | ||||
|             }; | ||||
|             else commentDialogList = new String[]{ | ||||
|                     resources.getString(R.string.open_profile) | ||||
|             }; | ||||
| 
 | ||||
|             commmentDialogAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, commentDialogList); | ||||
| 
 | ||||
|             new AlertDialog.Builder(this).setTitle(title) | ||||
|                     .setAdapter(commmentDialogAdapter, profileDialogListener) | ||||
|                     .setNeutralButton(R.string.cancel, null) | ||||
|                     .show(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     private final MentionClickListener mentionClickListener = (view, text, isHashtag) -> | ||||
|             new AlertDialog.Builder(this).setTitle(text) | ||||
|                     .setMessage(isHashtag ? R.string.comment_view_mention_hash_search : R.string.comment_view_mention_user_search) | ||||
|                     .setNegativeButton(R.string.cancel, null).setPositiveButton(R.string.ok, | ||||
|                     (dialog, which) -> searchUsername(text)).show(); | ||||
| 
 | ||||
| 
 | ||||
|     private void searchUsername(final String text) { | ||||
|         if (Main.scanHack != null) { | ||||
|             Main.scanHack.onResult(text); | ||||
|             setResult(6969); | ||||
|             finish(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -7,7 +7,6 @@ import android.graphics.drawable.Drawable; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Bundle; | ||||
| import android.os.Environment; | ||||
| import android.util.Log; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| @ -29,22 +28,14 @@ import awais.instagrabber.R; | ||||
| import awais.instagrabber.asyncs.DownloadAsync; | ||||
| import awais.instagrabber.asyncs.ProfilePictureFetcher; | ||||
| import awais.instagrabber.databinding.ActivityProfileBinding; | ||||
| import awais.instagrabber.dialogs.ProfileSettingsDialog; | ||||
| import awais.instagrabber.interfaces.FetchListener; | ||||
| import awais.instagrabber.models.HashtagModel; | ||||
| import awais.instagrabber.models.LocationModel; | ||||
| import awais.instagrabber.models.ProfileModel; | ||||
| import awais.instagrabber.models.enums.ProfilePictureFetchMode; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Constants.PROFILE_FETCH_MODE; | ||||
| 
 | ||||
| public final class ProfileViewer extends BaseLanguageActivity { | ||||
|     private final ProfilePictureFetchMode[] fetchModes = { | ||||
|             ProfilePictureFetchMode.INSTADP, | ||||
|             ProfilePictureFetchMode.INSTAFULLSIZE | ||||
|     }; | ||||
|     private ActivityProfileBinding profileBinding; | ||||
|     private ProfileModel profileModel; | ||||
|     private HashtagModel hashtagModel; | ||||
| @ -88,15 +79,12 @@ public final class ProfileViewer extends BaseLanguageActivity { | ||||
|         profileBinding.imageViewer.setZoomTransitionDuration(420); | ||||
|         profileBinding.imageViewer.setMaximumScale(7.2f); | ||||
| 
 | ||||
|         final int fetchIndex = Math.min(2, Math.max(0, Utils.settingsHelper.getInteger(PROFILE_FETCH_MODE))); | ||||
|         final ProfilePictureFetchMode fetchMode = fetchModes[fetchIndex]; | ||||
| 
 | ||||
|         fetchListener = profileUrl -> { | ||||
|             profilePicUrl = profileUrl; | ||||
| 
 | ||||
|             if (!fallbackToProfile && Utils.isEmpty(profilePicUrl)) { | ||||
|                 fallbackToProfile = true; | ||||
|                 new ProfilePictureFetcher(username, id, fetchListener, fetchMode, profilePicUrl, (hashtagModel != null || locationModel != null)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|                 new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
| @ -113,7 +101,7 @@ public final class ProfileViewer extends BaseLanguageActivity { | ||||
|                     fallbackToProfile = true; | ||||
|                     if (!errorHandled) { | ||||
|                         errorHandled = true; | ||||
|                         new ProfilePictureFetcher(username, id, fetchListener, fetchModes[Math.min(2, Math.max(0, fetchIndex + 1))], profilePicUrl, (hashtagModel != null || locationModel != null)) | ||||
|                         new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null)) | ||||
|                                 .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|                     } else { | ||||
|                         glideRequestManager.load(profilePicUrl).into(profileBinding.imageViewer); | ||||
| @ -168,7 +156,7 @@ public final class ProfileViewer extends BaseLanguageActivity { | ||||
|             }).into(profileBinding.imageViewer); | ||||
|         }; | ||||
| 
 | ||||
|         new ProfilePictureFetcher(username, id, fetchListener, fetchMode, profilePicUrl, (hashtagModel != null || locationModel != null)) | ||||
|         new ProfilePictureFetcher(username, id, fetchListener, profilePicUrl, (hashtagModel != null || locationModel != null)) | ||||
|                 .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | ||||
|     } | ||||
| 
 | ||||
| @ -211,8 +199,6 @@ public final class ProfileViewer extends BaseLanguageActivity { | ||||
|         final MenuItem.OnMenuItemClickListener menuItemClickListener = item -> { | ||||
|             if (item == menuItemDownload) { | ||||
|                 downloadProfilePicture(); | ||||
|             } else { | ||||
|                 new ProfileSettingsDialog().show(fragmentManager, "settings"); | ||||
|             } | ||||
|             return true; | ||||
|         }; | ||||
| @ -223,10 +209,6 @@ public final class ProfileViewer extends BaseLanguageActivity { | ||||
|         menuItemDownload.setEnabled(false); | ||||
|         menuItemDownload.setOnMenuItemClickListener(menuItemClickListener); | ||||
| 
 | ||||
|         final MenuItem menuItemSettings = menu.findItem(R.id.action_settings); | ||||
|         menuItemSettings.setVisible(true); | ||||
|         menuItemSettings.setOnMenuItemClickListener(menuItemClickListener); | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										90
									
								
								app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										90
									
								
								app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,90 @@ | ||||
| package awais.instagrabber.adapters; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.core.text.HtmlCompat; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import com.bumptech.glide.Glide; | ||||
| import com.bumptech.glide.RequestManager; | ||||
| import com.bumptech.glide.request.RequestOptions; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.viewholder.NotificationViewHolder; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.NotificationModel; | ||||
| import awais.instagrabber.utils.LocaleUtils; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| 
 | ||||
| public final class NotificationsAdapter extends RecyclerView.Adapter<NotificationViewHolder> { | ||||
|     private final View.OnClickListener onClickListener; | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final NotificationModel[] notificationModels; | ||||
|     private LayoutInflater layoutInflater; | ||||
| 
 | ||||
|     public NotificationsAdapter(final NotificationModel[] notificationModels, final View.OnClickListener onClickListener, | ||||
|                                 final MentionClickListener mentionClickListener) { | ||||
|         this.notificationModels = notificationModels; | ||||
|         this.onClickListener = onClickListener; | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public NotificationViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) { | ||||
|         final Context context = parent.getContext(); | ||||
|         if (layoutInflater == null) layoutInflater = LayoutInflater.from(context); | ||||
|         return new NotificationViewHolder(layoutInflater.inflate(R.layout.item_notification, | ||||
|                 parent, false), onClickListener, mentionClickListener); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull final NotificationViewHolder holder, final int position) { | ||||
|         final NotificationModel notificationModel = notificationModels[position]; | ||||
|         if (notificationModel != null) { | ||||
|             holder.setNotificationModel(notificationModel); | ||||
| 
 | ||||
|             int text = -1; | ||||
|             CharSequence subtext = null; | ||||
|             switch (notificationModel.getType()) { | ||||
|                 case LIKE: | ||||
|                     text = R.string.liked_notif; | ||||
|                     break; | ||||
|                 case COMMENT: | ||||
|                     text = R.string.comment_notif; | ||||
|                     subtext = notificationModel.getText(); | ||||
|                     break; | ||||
|                 case MENTION: | ||||
|                     text = R.string.mention_notif; | ||||
|                     subtext = notificationModel.getText(); | ||||
|                     break; | ||||
|                 case FOLLOW: | ||||
|                     text = R.string.follow_notif; | ||||
|                     break; | ||||
|             } | ||||
| 
 | ||||
|             holder.setCommment(text); | ||||
|             holder.setSubCommment(subtext); | ||||
|             holder.setDate(notificationModel.getDateTime()); | ||||
| 
 | ||||
|             holder.setUsername(notificationModel.getUsername()); | ||||
| 
 | ||||
|             final RequestManager rm = Glide.with(layoutInflater.getContext()) | ||||
|                     .applyDefaultRequestOptions(new RequestOptions().skipMemoryCache(true)); | ||||
| 
 | ||||
|             rm.load(notificationModel.getProfilePic()).into(holder.getProfilePicView()); | ||||
|             rm.load(notificationModel.getPreviewPic()).into(holder.getPreviewPicView()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return notificationModels == null ? 0 : notificationModels.length; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,76 @@ | ||||
| package awais.instagrabber.adapters.viewholder; | ||||
| 
 | ||||
| import android.text.Spannable; | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| import awais.instagrabber.adapters.CommentsAdapter; | ||||
| import awais.instagrabber.customviews.RamboTextView; | ||||
| import awais.instagrabber.interfaces.MentionClickListener; | ||||
| import awais.instagrabber.models.NotificationModel; | ||||
| 
 | ||||
| public final class NotificationViewHolder extends RecyclerView.ViewHolder { | ||||
|     private final MentionClickListener mentionClickListener; | ||||
|     private final ImageView ivProfilePic, ivPreviewPic; | ||||
|     private final TextView tvUsername, tvDate, tvComment, tvSubComment; | ||||
|     private final View container, rightContainer; | ||||
| 
 | ||||
|     public NotificationViewHolder(@NonNull final View itemView, final View.OnClickListener onClickListener, final MentionClickListener mentionClickListener) { | ||||
|         super(itemView); | ||||
| 
 | ||||
|         container = itemView.findViewById(R.id.container); | ||||
|         rightContainer = itemView.findViewById(R.id.rightContainer); | ||||
|         if (onClickListener != null) container.setOnClickListener(onClickListener); | ||||
| 
 | ||||
|         this.mentionClickListener = mentionClickListener; | ||||
| 
 | ||||
|         ivProfilePic = itemView.findViewById(R.id.ivProfilePic); | ||||
|         ivPreviewPic = itemView.findViewById(R.id.ivPreviewPic); | ||||
|         tvUsername = itemView.findViewById(R.id.tvUsername); | ||||
|         tvDate = itemView.findViewById(R.id.tvDate); | ||||
|         tvComment = itemView.findViewById(R.id.tvComment); | ||||
|         tvSubComment = itemView.findViewById(R.id.tvSubComment); | ||||
| 
 | ||||
|         tvUsername.setSelected(true); | ||||
|         tvDate.setSelected(true); | ||||
|     } | ||||
| 
 | ||||
|     public final ImageView getProfilePicView() { | ||||
|         return ivProfilePic; | ||||
|     } | ||||
| 
 | ||||
|     public final ImageView getPreviewPicView() { | ||||
|         return ivPreviewPic; | ||||
|     } | ||||
| 
 | ||||
|     public final void setNotificationModel(final NotificationModel notificationModel) { | ||||
|         if (container != null) container.setTag(notificationModel); | ||||
|         if (rightContainer != null) rightContainer.setTag(notificationModel); | ||||
|     } | ||||
| 
 | ||||
|     public final void setUsername(final String username) { | ||||
|         if (tvUsername != null) tvUsername.setText(username); | ||||
|     } | ||||
| 
 | ||||
|     public final void setDate(final String date) { | ||||
|         if (tvDate != null) tvDate.setText(date); | ||||
|     } | ||||
| 
 | ||||
|     public final void setCommment(final int commment) { | ||||
|         if (tvComment != null) { | ||||
|             tvComment.setText(commment); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public final void setSubCommment(final CharSequence commment) { | ||||
|         if (tvSubComment != null) { | ||||
|             tvSubComment.setText(commment, commment instanceof Spannable ? TextView.BufferType.SPANNABLE : TextView.BufferType.NORMAL); | ||||
|             ((RamboTextView) tvSubComment).setMentionClickListener(mentionClickListener); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										85
									
								
								app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										85
									
								
								app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,85 @@ | ||||
| package awais.instagrabber.asyncs; | ||||
| 
 | ||||
| import android.os.AsyncTask; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| import awais.instagrabber.BuildConfig; | ||||
| import awais.instagrabber.interfaces.FetchListener; | ||||
| import awais.instagrabber.models.NotificationModel; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awaisomereport.LogCollector; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Utils.logCollector; | ||||
| 
 | ||||
| public final class NotificationsFetcher extends AsyncTask<Void, Void, NotificationModel[]> { | ||||
|     private final FetchListener<NotificationModel[]> fetchListener; | ||||
| 
 | ||||
|     public NotificationsFetcher(final FetchListener<NotificationModel[]> fetchListener) { | ||||
|         this.fetchListener = fetchListener; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected NotificationModel[] doInBackground(final Void... voids) { | ||||
|         NotificationModel[] result = null; | ||||
|         final String url = "https://www.instagram.com/accounts/activity/?__a=1"; | ||||
| 
 | ||||
|         try { | ||||
|             final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); | ||||
|             conn.setInstanceFollowRedirects(false); | ||||
|             conn.setUseCaches(false); | ||||
|             conn.connect(); | ||||
| 
 | ||||
|             if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { | ||||
|                 JSONObject data = new JSONObject(Utils.readFromConnection(conn)) | ||||
|                         .getJSONObject("graphql").getJSONObject("user").getJSONObject("activity_feed").getJSONObject("edge_web_activity_feed"); | ||||
| 
 | ||||
|                 JSONArray media; | ||||
|                 if ((media = data.optJSONArray("edges")) != null && media.length() > 0 && | ||||
|                         (data = media.optJSONObject(0).optJSONObject("node")) != null) { | ||||
| 
 | ||||
|                     final int mediaLen = media.length(); | ||||
| 
 | ||||
|                     final NotificationModel[] models = new NotificationModel[mediaLen]; | ||||
|                     for (int i = 0; i < mediaLen; ++i) { | ||||
|                         data = media.optJSONObject(i).optJSONObject("node"); | ||||
|                         if (Utils.getNotifType(data.getString("__typename")) == null) continue; | ||||
|                         models[i] = new NotificationModel(data.getString(Constants.EXTRAS_ID), | ||||
|                                 data.optString("text"), // comments or mentions | ||||
|                                 data.getLong("timestamp"), | ||||
|                                 data.getJSONObject("user").getString("username"), | ||||
|                                 data.getJSONObject("user").getString("profile_pic_url"), | ||||
|                                 !data.isNull("media") ? data.getJSONObject("media").getString("shortcode") : null, | ||||
|                                 !data.isNull("media") ? data.getJSONObject("media").getString("thumbnail_src") : null, | ||||
|                                 Utils.getNotifType(data.getString("__typename"))); | ||||
|                     } | ||||
|                     result = models; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             conn.disconnect(); | ||||
|         } catch (final Exception e) { | ||||
|             if (logCollector != null) | ||||
|                 logCollector.appendException(e, LogCollector.LogFile.ASYNC_NOTIFICATION_FETCHER, "doInBackground"); | ||||
|             if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPreExecute() { | ||||
|         if (fetchListener != null) fetchListener.doBefore(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(final NotificationModel[] result) { | ||||
|         if (fetchListener != null) fetchListener.onResult(result); | ||||
|     } | ||||
| } | ||||
| @ -5,31 +5,26 @@ import android.util.Log; | ||||
| import android.util.Pair; | ||||
| 
 | ||||
| import org.json.JSONObject; | ||||
| import org.jsoup.Jsoup; | ||||
| import org.jsoup.nodes.Document; | ||||
| import org.jsoup.nodes.Element; | ||||
| import org.jsoup.select.Elements; | ||||
| 
 | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| import awais.instagrabber.BuildConfig; | ||||
| import awais.instagrabber.interfaces.FetchListener; | ||||
| import awais.instagrabber.utils.Constants; | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awaisomereport.LogCollector; | ||||
| import awais.instagrabber.models.enums.ProfilePictureFetchMode; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Utils.logCollector; | ||||
| 
 | ||||
| public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> { | ||||
|     private final FetchListener<String> fetchListener; | ||||
|     private final String userName, userId, picUrl; | ||||
|     private final boolean isHashtag; | ||||
|     private ProfilePictureFetchMode fetchMode; | ||||
| 
 | ||||
|     public ProfilePictureFetcher(final String userName, final String userId, final FetchListener<String> fetchListener, | ||||
|                                  final ProfilePictureFetchMode fetchMode, final String picUrl, final boolean isHashtag) { | ||||
|                                  final String picUrl, final boolean isHashtag) { | ||||
|         this.fetchListener = fetchListener; | ||||
|         this.fetchMode = fetchMode; | ||||
|         this.userName = userName; | ||||
|         this.userId = userId; | ||||
|         this.picUrl = picUrl; | ||||
| @ -40,69 +35,28 @@ public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> { | ||||
|     protected String doInBackground(final Void... voids) { | ||||
|         String out = picUrl; | ||||
|         if (!isHashtag) try { | ||||
|             if (fetchMode == ProfilePictureFetchMode.INSTA_STALKER) fetchMode = ProfilePictureFetchMode.INSTADP; | ||||
|             final String url; | ||||
| 
 | ||||
|             if (fetchMode == ProfilePictureFetchMode.INSTADP) | ||||
|                 url = "https://instadp.com/fullsize/" + userName; | ||||
|             else // select from s1, s2, s3 but s1 works fine | ||||
|                 url = "https://instafullsize.com/ifsapi/ig/photo/s1/" + userName + "?igid=" + userId; | ||||
| 
 | ||||
|             // prolly http://167.99.85.4/instagram/userid?profile-url=the.badak | ||||
|             final String url = "https://i.instagram.com/api/v1/users/"+userId+"/info/"; | ||||
| 
 | ||||
|             final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); | ||||
|             conn.setUseCaches(false); | ||||
| 
 | ||||
|             if (fetchMode == ProfilePictureFetchMode.INSTAFULLSIZE) { | ||||
|                 conn.setRequestMethod("GET"); | ||||
|                 conn.setRequestProperty("Authorization", "fjgt842ff582a"); | ||||
|             } | ||||
|             conn.setRequestMethod("GET"); | ||||
|             conn.setRequestProperty("User-Agent", Constants.USER_AGENT); | ||||
| 
 | ||||
|             final String result = conn.getResponseCode() == HttpURLConnection.HTTP_OK ? Utils.readFromConnection(conn) : null; | ||||
|             conn.disconnect(); | ||||
| 
 | ||||
|             if (!Utils.isEmpty(result)) { | ||||
|                 final Document doc = Jsoup.parse(result); | ||||
|                 boolean fallback = false; | ||||
| 
 | ||||
|                 if (fetchMode == ProfilePictureFetchMode.INSTADP) { | ||||
|                     final int imgIndex = result.indexOf("preloadImg('"), lastIndex; | ||||
| 
 | ||||
|                     Element element = doc.selectFirst(".instadp"); | ||||
|                     if (element != null && (element = element.selectFirst(".picture")) != null) | ||||
|                         out = element.attr("src"); | ||||
|                     else if ((element = doc.selectFirst(".download-btn")) != null) | ||||
|                         out = element.attr("href"); | ||||
|                     else if (imgIndex != -1 && (lastIndex = result.indexOf("')", imgIndex)) != -1) | ||||
|                         out = result.substring(imgIndex + 12, lastIndex); | ||||
|                     else fallback = true; | ||||
| 
 | ||||
|                 } else if (fetchMode == ProfilePictureFetchMode.INSTAFULLSIZE) { | ||||
|                     try { | ||||
|                         final JSONObject object = new JSONObject(result); | ||||
|                         out = object.getString("result"); | ||||
|                     } catch (final Exception e) { | ||||
|                         if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); | ||||
|                         fallback = true; | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|                 if (fallback) { | ||||
|                     final Elements imgs = doc.getElementsByTag("img"); | ||||
|                     for (final Element img : imgs) { | ||||
|                         final String imgStr = img.toString(); | ||||
|                         if (imgStr.contains("cdninstagram.com")) return img.attr("src"); | ||||
|                     } | ||||
|                 } | ||||
|                 JSONObject data = new JSONObject(result).getJSONObject("user"); | ||||
|                 if (data.has("hd_profile_pic_url_info")) | ||||
|                     out = data.getJSONObject("hd_profile_pic_url_info").optString("url"); | ||||
|             } | ||||
|         } catch (final Exception e) { | ||||
|             if (logCollector != null) | ||||
|                 logCollector.appendException(e, LogCollector.LogFile.ASYNC_PROFILE_PICTURE_FETCHER, "doInBackground", | ||||
|                         new Pair<>("fetchMode", fetchMode)); | ||||
|                 logCollector.appendException(e, LogCollector.LogFile.ASYNC_PROFILE_PICTURE_FETCHER, "doInBackground"); | ||||
|             if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); | ||||
|         } | ||||
| 
 | ||||
|         if (out == null) out = picUrl; | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,62 +0,0 @@ | ||||
| package awais.instagrabber.dialogs; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.app.Dialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import android.widget.AdapterView; | ||||
| import android.widget.Spinner; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import com.google.android.material.bottomsheet.BottomSheetDialogFragment; | ||||
| 
 | ||||
| import awais.instagrabber.R; | ||||
| 
 | ||||
| import static awais.instagrabber.utils.Constants.PROFILE_FETCH_MODE; | ||||
| import static awais.instagrabber.utils.Utils.settingsHelper; | ||||
| 
 | ||||
| public final class ProfileSettingsDialog extends BottomSheetDialogFragment implements AdapterView.OnItemSelectedListener { | ||||
|     private int fetchIndex; | ||||
|     private Activity activity; | ||||
|     private Spinner spProfileFetchMode; | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { | ||||
|         final Dialog dialog = super.onCreateDialog(savedInstanceState); | ||||
| 
 | ||||
|         final Context context = getContext(); | ||||
|         activity = context instanceof Activity ? (Activity) context : getActivity(); | ||||
| 
 | ||||
|         final View contentView = View.inflate(activity, R.layout.dialog_profile_settings, null); | ||||
| 
 | ||||
|         spProfileFetchMode = contentView.findViewById(R.id.spProfileFetchMode); | ||||
| 
 | ||||
|         fetchIndex = Math.min(2, Math.max(0, settingsHelper.getInteger(PROFILE_FETCH_MODE))); | ||||
|         spProfileFetchMode.setSelection(fetchIndex); | ||||
|         spProfileFetchMode.setOnItemSelectedListener(this); | ||||
| 
 | ||||
|         dialog.setContentView(contentView); | ||||
| 
 | ||||
|         return dialog; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onDismiss(@NonNull final DialogInterface dialog) { | ||||
|         super.onDismiss(dialog); | ||||
|         if (activity != null && (spProfileFetchMode == null || fetchIndex != spProfileFetchMode.getSelectedItemPosition())) | ||||
|             activity.recreate(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) { | ||||
|         settingsHelper.putInteger(PROFILE_FETCH_MODE, position); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onNothingSelected(final AdapterView<?> parent) { } | ||||
| } | ||||
							
								
								
									
										58
									
								
								app/src/main/java/awais/instagrabber/models/NotificationModel.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										58
									
								
								app/src/main/java/awais/instagrabber/models/NotificationModel.java
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,58 @@ | ||||
| package awais.instagrabber.models; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.Date; | ||||
| 
 | ||||
| import awais.instagrabber.utils.Utils; | ||||
| import awais.instagrabber.models.enums.NotificationType; | ||||
| 
 | ||||
| public final class NotificationModel { | ||||
|     private final String id, username, profilePicUrl, shortcode, previewUrl; | ||||
|     private final NotificationType type; | ||||
|     private final CharSequence text; | ||||
|     private final long timestamp; | ||||
| 
 | ||||
|     public NotificationModel(final String id, final String text, final long timestamp, final String username, | ||||
|                              final String profilePicUrl, final String shortcode, final String previewUrl, final NotificationType type) { | ||||
|         this.id = id; | ||||
|         this.text = Utils.hasMentions(text) ? Utils.getMentionText(text) : text; | ||||
|         this.timestamp = timestamp; | ||||
|         this.username = username; | ||||
|         this.profilePicUrl = profilePicUrl; | ||||
|         this.shortcode = shortcode; | ||||
|         this.previewUrl = previewUrl; | ||||
|         this.type = type; | ||||
|     } | ||||
| 
 | ||||
|     public String getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public CharSequence getText() { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public String getDateTime() { | ||||
|         return Utils.datetimeParser.format(new Date(timestamp * 1000L)); | ||||
|     } | ||||
| 
 | ||||
|     public String getUsername() { | ||||
|         return username; | ||||
|     } | ||||
| 
 | ||||
|     public String getProfilePic() { | ||||
|         return profilePicUrl; | ||||
|     } | ||||
| 
 | ||||
|     public String getShortcode() { | ||||
|         return shortcode; | ||||
|     } | ||||
| 
 | ||||
|     public String getPreviewPic() { | ||||
|         return previewUrl; | ||||
|     } | ||||
| 
 | ||||
|     public NotificationType getType() { return type; } | ||||
| } | ||||
							
								
								
									
										10
									
								
								app/src/main/java/awais/instagrabber/models/enums/NotificationType.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/java/awais/instagrabber/models/enums/NotificationType.java
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,10 @@ | ||||
| package awais.instagrabber.models.enums; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| public enum NotificationType implements Serializable { | ||||
|     LIKE, | ||||
|     FOLLOW, | ||||
|     COMMENT, | ||||
|     MENTION | ||||
| } | ||||
| @ -1,7 +0,0 @@ | ||||
| package awais.instagrabber.models.enums; | ||||
| 
 | ||||
| public enum ProfilePictureFetchMode { | ||||
|     INSTADP, | ||||
|     INSTAFULLSIZE, | ||||
|     INSTA_STALKER, | ||||
| } | ||||
| @ -10,7 +10,6 @@ public final class Constants { | ||||
|     public static final String APP_THEME = "app_theme"; | ||||
|     public static final String APP_LANGUAGE = "app_language"; | ||||
|     public static final String PREV_INSTALL_VERSION = "prevVersion"; | ||||
|     public static final String PROFILE_FETCH_MODE = "profile_fetch_mode"; | ||||
|     // boolean prefs | ||||
|     public static final String DOWNLOAD_USER_FOLDER = "download_user_folder"; | ||||
|     public static final String BOTTOM_TOOLBAR = "bottom_toolbar"; | ||||
|  | ||||
| @ -219,7 +219,6 @@ public final class ExportImportUtils { | ||||
|                 final JSONObject json = new JSONObject(); | ||||
|                 json.put(Constants.APP_THEME, settingsHelper.getInteger(Constants.APP_THEME)); | ||||
|                 json.put(Constants.APP_LANGUAGE, settingsHelper.getInteger(Constants.APP_LANGUAGE)); | ||||
|                 json.put(Constants.PROFILE_FETCH_MODE, settingsHelper.getInteger(Constants.PROFILE_FETCH_MODE)); | ||||
| 
 | ||||
|                 String str = settingsHelper.getString(Constants.FOLDER_PATH); | ||||
|                 if (!Utils.isEmpty(str)) json.put(Constants.FOLDER_PATH, str); | ||||
|  | ||||
| @ -23,7 +23,6 @@ import static awais.instagrabber.utils.Constants.FOLDER_PATH; | ||||
| import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO; | ||||
| import static awais.instagrabber.utils.Constants.MUTED_VIDEOS; | ||||
| import static awais.instagrabber.utils.Constants.PREV_INSTALL_VERSION; | ||||
| import static awais.instagrabber.utils.Constants.PROFILE_FETCH_MODE; | ||||
| import static awais.instagrabber.utils.Constants.SHOW_QUICK_ACCESS_DIALOG; | ||||
| 
 | ||||
| public final class SettingsHelper { | ||||
| @ -109,6 +108,6 @@ public final class SettingsHelper { | ||||
|             AUTOLOAD_POSTS, CUSTOM_DATE_TIME_FORMAT_ENABLED}) | ||||
|     public @interface BooleanSettings {} | ||||
| 
 | ||||
|     @StringDef({APP_THEME, APP_LANGUAGE, PROFILE_FETCH_MODE, PREV_INSTALL_VERSION}) | ||||
|     @StringDef({APP_THEME, APP_LANGUAGE, PREV_INSTALL_VERSION}) | ||||
|     public @interface IntegerSettings {} | ||||
| } | ||||
| @ -82,6 +82,7 @@ import awais.instagrabber.models.enums.DownloadMethod; | ||||
| import awais.instagrabber.models.enums.InboxReadState; | ||||
| import awais.instagrabber.models.enums.IntentModelType; | ||||
| import awais.instagrabber.models.enums.MediaItemType; | ||||
| import awais.instagrabber.models.enums.NotificationType; | ||||
| import awais.instagrabber.models.enums.RavenExpiringMediaType; | ||||
| import awais.instagrabber.models.enums.RavenMediaViewType; | ||||
| import awaisomereport.LogCollector; | ||||
| @ -128,6 +129,7 @@ public final class Utils { | ||||
|             try { | ||||
|                 final URI uri1 = new URI("https://instagram.com"); | ||||
|                 final URI uri2 = new URI("https://instagram.com/"); | ||||
|                 final URI uri3 = new URI("https://i.instagram.com/"); | ||||
|                 for (final String cookie : cookieRaw.split(";")) { | ||||
|                     final String[] strings = cookie.split("=", 2); | ||||
|                     final HttpCookie httpCookie = new HttpCookie(strings[0].trim(), strings[1].trim()); | ||||
| @ -136,6 +138,7 @@ public final class Utils { | ||||
|                     httpCookie.setVersion(0); | ||||
|                     cookieStore.add(uri1, httpCookie); | ||||
|                     cookieStore.add(uri2, httpCookie); | ||||
|                     cookieStore.add(uri3, httpCookie); | ||||
|                 } | ||||
|             } catch (final URISyntaxException e) { | ||||
|                 if (logCollector != null) | ||||
| @ -732,6 +735,14 @@ public final class Utils { | ||||
|         return RavenExpiringMediaType.RAVEN_UNKNOWN; | ||||
|     } | ||||
| 
 | ||||
|     public static NotificationType getNotifType(final String itemType) { | ||||
|         if ("GraphLikeAggregatedStory".equals(itemType)) return NotificationType.LIKE; | ||||
|         if ("GraphFollowAggregatedStory".equals(itemType)) return NotificationType.FOLLOW; | ||||
|         if ("GraphCommentMediaStory".equals(itemType)) return NotificationType.COMMENT; | ||||
|         if ("GraphMentionStory".equals(itemType)) return NotificationType.MENTION; | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public static int convertDpToPx(final float dp) { | ||||
|         if (displayMetrics == null) | ||||
|             displayMetrics = Resources.getSystem().getDisplayMetrics(); | ||||
| @ -1189,7 +1200,7 @@ public final class Utils { | ||||
|                             if (jsonObject.getString("__typename").equals("GraphTappableFeedMedia") && jsonObject.has("media")) { | ||||
|                                 storyModels[j].setTappableShortCode(jsonObject.getJSONObject("media").getString(Constants.EXTRAS_SHORTCODE)); | ||||
|                             } | ||||
|                             else if (jsonObject.optString("__typename").equals("GraphTappableStoryPoll")) { | ||||
|                             else if (jsonObject.optString("__typename").equals("GraphTappableStoryPoll") && !jsonObject.isNull("id")) { | ||||
|                                 storyModels[j].setPoll(new PollModel( | ||||
|                                         jsonObject.getString("id"), | ||||
|                                         jsonObject.getString("question"), | ||||
|  | ||||
| @ -108,6 +108,7 @@ public final class LogCollector { | ||||
|         ASYNC_FEED_FETCHER("async-feed-fetcher.txt"), | ||||
|         ASYNC_HASHTAG_FETCHER("async-hashtag-fetcher.txt"), | ||||
|         ASYNC_LOCATION_FETCHER("async-location-fetcher.txt"), | ||||
|         ASYNC_NOTIFICATION_FETCHER("async-notification-fetcher.txt"), | ||||
|         ASYNC_PROFILE_FETCHER("async-profile-fetcher.txt"), | ||||
|         ASYNC_PROFILE_PICTURE_FETCHER("async-pfp-fetcher.txt"), | ||||
|         ASYNC_SAVED_FETCHER("async-saved-fetcher.txt"), | ||||
|  | ||||
							
								
								
									
										11
									
								
								app/src/main/res/drawable-anydpi/ic_notif.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/src/main/res/drawable-anydpi/ic_notif.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="#333333" | ||||
|     android:alpha="0.6"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/> | ||||
| </vector> | ||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-hdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-hdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 269 B | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 193 B | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xhdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xhdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 321 B | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_notif.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 433 B | 
							
								
								
									
										30
									
								
								app/src/main/res/layout/activity_notification.xml
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										30
									
								
								app/src/main/res/layout/activity_notification.xml
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,30 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical" | ||||
|     tools:context=".activities.NotificationsViewer"> | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/toolbar" | ||||
|         layout="@layout/layout_include_toolbar" /> | ||||
| 
 | ||||
|     <androidx.swiperefreshlayout.widget.SwipeRefreshLayout | ||||
|         android:id="@+id/swipeRefreshLayout" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent"> | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:id="@+id/rvComments" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:clipToPadding="false" | ||||
|             android:paddingStart="8dp" | ||||
|             android:paddingLeft="8dp" | ||||
|             android:paddingEnd="8dp" | ||||
|             android:paddingRight="8dp" | ||||
|             app:layoutManager="LinearLayoutManager" | ||||
|             tools:listitem="@layout/item_notification" /> | ||||
|     </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | ||||
| </LinearLayout> | ||||
| @ -1,48 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical" | ||||
|     android:paddingBottom="10dp"> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.AppCompatTextView | ||||
|         style="@style/TextAppearance.AppCompat.Headline" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:ellipsize="end" | ||||
|         android:paddingStart="?attr/dialogPreferredPadding" | ||||
|         android:paddingLeft="?attr/dialogPreferredPadding" | ||||
|         android:paddingTop="10dp" | ||||
|         android:paddingEnd="?attr/dialogPreferredPadding" | ||||
|         android:paddingRight="?attr/dialogPreferredPadding" | ||||
|         android:paddingBottom="6dp" | ||||
|         android:singleLine="true" | ||||
|         android:text="@string/action_settings" /> | ||||
| 
 | ||||
|     <androidx.appcompat.widget.LinearLayoutCompat | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="5dp" | ||||
|         android:layout_marginLeft="5dp" | ||||
|         android:orientation="vertical" | ||||
|         android:layout_marginBottom="24dp" | ||||
|         android:padding="5dp"> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:gravity="center_vertical" | ||||
|             android:padding="5dp" | ||||
|             android:text="@string/profile_endpoint" | ||||
|             android:textColor="?android:textColorPrimary" | ||||
|             android:textSize="16sp" /> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatSpinner | ||||
|             android:id="@+id/spProfileFetchMode" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:entries="@array/profile_fetch_modes" | ||||
|             android:paddingTop="4dp" | ||||
|             android:paddingBottom="4dp" /> | ||||
|     </androidx.appcompat.widget.LinearLayoutCompat> | ||||
| </androidx.appcompat.widget.LinearLayoutCompat> | ||||
							
								
								
									
										20
									
								
								app/src/main/res/layout/item_notification.xml
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										20
									
								
								app/src/main/res/layout/item_notification.xml
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:orientation="vertical" | ||||
|     tools:viewBindingIgnore="true"> | ||||
| 
 | ||||
|     <include | ||||
|         android:id="@+id/container" | ||||
|         layout="@layout/layout_include_notif_item" /> | ||||
| 
 | ||||
|     <View | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="1dp" | ||||
|         android:layout_gravity="bottom" | ||||
|         android:layout_marginBottom="4dp" | ||||
|         android:background="#80888888" /> | ||||
| </LinearLayout> | ||||
| @ -1,18 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:clipChildren="false" | ||||
|     android:clipToPadding="false"> | ||||
| 
 | ||||
|     <awais.instagrabber.customviews.RamboTextView | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:paddingStart="10dp" | ||||
|         android:paddingLeft="10dp" | ||||
|         android:paddingEnd="10dp" | ||||
|         android:paddingRight="10dp" | ||||
|         android:paddingBottom="24dp" | ||||
|         android:textAppearance="@style/TextAppearance.AppCompat.Body1" | ||||
|         android:textSize="16sp" /> | ||||
| </ScrollView> | ||||
							
								
								
									
										154
									
								
								app/src/main/res/layout/layout_include_notif_item.xml
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										154
									
								
								app/src/main/res/layout/layout_include_notif_item.xml
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,154 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:background="?android:selectableItemBackground" | ||||
|     android:orientation="horizontal" | ||||
|     android:paddingStart="0dp" | ||||
|     android:paddingLeft="0dp" | ||||
|     android:paddingEnd="4dp" | ||||
|     android:paddingRight="4dp"> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:layout_width="@dimen/simple_item_picture_size" | ||||
|         android:layout_height="@dimen/simple_item_picture_size" | ||||
|         android:gravity="center"> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatImageView | ||||
|             android:id="@+id/ivProfilePic" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" /> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:id="@+id/container" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:orientation="horizontal"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageView | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" /> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatImageView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" /> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatImageView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" /> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </FrameLayout> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_weight="1" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:orientation="vertical"> | ||||
| 
 | ||||
|             <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" /> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:orientation="vertical" | ||||
|             android:paddingLeft="8dp" | ||||
|             android:paddingTop="4dp" | ||||
|             android:paddingRight="8dp"> | ||||
| 
 | ||||
|             <awais.instagrabber.customviews.RamboTextView | ||||
|                 android:id="@+id/tvComment" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_gravity="start" | ||||
|                 android:ellipsize="end" | ||||
|                 android:linksClickable="true" | ||||
|                 android:textStyle="italic" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat" /> | ||||
| 
 | ||||
|             <awais.instagrabber.customviews.RamboTextView | ||||
|                 android:id="@+id/tvSubComment" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_gravity="start" | ||||
|                 android:autoLink="web|email" | ||||
|                 android:ellipsize="end" | ||||
|                 android:linksClickable="true" | ||||
|                 android:textAppearance="@style/TextAppearance.AppCompat" /> | ||||
|         </LinearLayout> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatTextView | ||||
|             android:id="@+id/tvDate" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="start" | ||||
|             android:ellipsize="marquee" | ||||
|             android:gravity="right" | ||||
|             android:paddingStart="4dp" | ||||
|             android:paddingLeft="4dp" | ||||
|             android:paddingTop="4dp" | ||||
|             android:paddingEnd="8dp" | ||||
|             android:paddingRight="8dp" | ||||
|             android:singleLine="true" | ||||
|             android:textStyle="italic" /> | ||||
| 
 | ||||
|     </LinearLayout> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:layout_width="@dimen/simple_item_picture_size" | ||||
|         android:layout_height="@dimen/simple_item_picture_size" | ||||
|         android:gravity="center"> | ||||
| 
 | ||||
|         <androidx.appcompat.widget.AppCompatImageView | ||||
|             android:id="@+id/ivPreviewPic" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" /> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:id="@+id/rightContainer" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:orientation="horizontal"> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageView | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" /> | ||||
| 
 | ||||
|             <LinearLayout | ||||
|                 android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatImageView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" /> | ||||
| 
 | ||||
|                 <androidx.appcompat.widget.AppCompatImageView | ||||
|                     android:layout_width="@dimen/simple_item_picture_size_half" | ||||
|                     android:layout_height="@dimen/simple_item_picture_size_half" /> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </FrameLayout> | ||||
| </LinearLayout> | ||||
| @ -12,6 +12,14 @@ | ||||
|         android:visible="false" | ||||
|         app:showAsAction="always" /> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/action_notif" | ||||
|         android:icon="@drawable/ic_notif" | ||||
|         android:title="@string/action_notif" | ||||
|         android:titleCondensed="@string/action_notif" | ||||
|         android:visible="false" | ||||
|         app:showAsAction="ifRoom" /> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/action_about" | ||||
|         android:icon="@android:drawable/ic_menu_info_details" | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>tanggal</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -25,10 +25,6 @@ | ||||
|         <item>\|</item> | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -28,11 +28,6 @@ | ||||
|         <item>-</item> | ||||
|     </string-array> | ||||
| 
 | ||||
|     <string-array name="profile_fetch_modes"> | ||||
|         <item>Instadp</item> | ||||
|         <item>Instafullsize</item> | ||||
|     </string-array> | ||||
| 
 | ||||
|     <string-array name="date_presets"> | ||||
|         <item>dd-MM-yyyy</item> | ||||
|         <item>dd/MM/yyyy</item> | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
|     <string name="description">The original maintainer, AWAiS, made InstaGrabber as a small and basic little personal app with intentions of [steali-]downloading posts off Instagram. Very unfortunately, this was abandoned and me, Austin Huang, took over the ship. [Let\'s hope that\'s at least a lil\' bit cash money.] After all, this app is fully open source, ad-less, and tracking-less [aside from what Instagram knows]. Even if you don\'t care about downloading stuff [like me], it\'s still a great Instagram client to use!\n\nGot questions [or just wanna talk]? Contact instagrabber@austinhuang.me or click one of the buttons below.</string> | ||||
|     <string name="action_quickaccess">Quick Access</string> | ||||
|     <string name="action_about">About</string> | ||||
|     <string name="action_notif">Notifications</string> | ||||
|     <string name="action_dms">Direct Messages</string> | ||||
|     <string name="action_setting">Settings (v%s)</string> | ||||
|     <string name="action_settings">Settings</string> | ||||
| @ -29,6 +30,7 @@ | ||||
|     <string name="title_favorites">Favorites</string> | ||||
|     <string name="title_discover">Discover</string> | ||||
|     <string name="title_comments">Comments</string> | ||||
|     <string name="title_notifications">Notifications</string> | ||||
|     <string name="title_highlight">Highlight: %s</string> | ||||
|     <string name="title_user_story">User Story</string> | ||||
|     <string name="title_changelog">Changelog</string> | ||||
| @ -60,6 +62,7 @@ | ||||
|     <string name="show_stories">Show stories</string> | ||||
|     <string name="no_more_stories">No more stories!</string> | ||||
|     <string name="view_story_post">View Story Post</string> | ||||
|     <string name="view_post">View Post</string> | ||||
|     <string name="spotify">Spotify</string> | ||||
|     <string name="vote_story_poll">Vote</string> | ||||
|     <string name="votef_story_poll">Vote successful!</string> | ||||
| @ -180,6 +183,11 @@ | ||||
| 
 | ||||
|     <string name="comment_hint">Write a new comment...</string> | ||||
| 
 | ||||
|     <string name="liked_notif">Liked your post</string> | ||||
|     <string name="comment_notif">Commented on your post:</string> | ||||
|     <string name="follow_notif">Started following you</string> | ||||
|     <string name="mention_notif">Mentioned you:</string> | ||||
| 
 | ||||
|     <string name="share_public_post">Share this public post to...</string> | ||||
|     <string name="share_private_post">This is a private post! Share to those who can view them!</string> | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user