1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-08 07:57:28 +00:00

Merge branch 'master' into master

This commit is contained in:
Austin Huang 2021-03-20 11:30:59 -04:00 committed by GitHub
commit 700711f5f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 330 additions and 6209 deletions

View File

@ -111,7 +111,6 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'org.apache.commons:commons-imaging:1.0-alpha2' implementation 'org.apache.commons:commons-imaging:1.0-alpha2'
implementation 'com.ibm.icu:icu4j:68.1'
implementation 'com.github.ammargitham:uCrop:2.3-native-beta-2' implementation 'com.github.ammargitham:uCrop:2.3-native-beta-2'
implementation 'com.github.ammargitham:android-gpuimage:2.1.1-beta4' implementation 'com.github.ammargitham:android-gpuimage:2.1.1-beta4'

View File

@ -22,7 +22,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme.Light.White" android:theme="@style/AppTheme.Launcher"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<activity <activity
android:name=".activities.MainActivity" android:name=".activities.MainActivity"

View File

@ -72,7 +72,6 @@ import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.models.IntentModel; import awais.instagrabber.models.IntentModel;
import awais.instagrabber.models.SuggestionModel; import awais.instagrabber.models.SuggestionModel;
import awais.instagrabber.models.enums.SuggestionType; import awais.instagrabber.models.enums.SuggestionType;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.services.ActivityCheckerService; import awais.instagrabber.services.ActivityCheckerService;
import awais.instagrabber.services.DMSyncAlarmReceiver; import awais.instagrabber.services.DMSyncAlarmReceiver;
import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.AppExecutors;
@ -251,7 +250,17 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (isTaskRoot() && isBackStackEmpty) { int currentNavControllerBackStack = 2;
if (currentNavControllerLiveData != null) {
final NavController navController = currentNavControllerLiveData.getValue();
if (navController != null) {
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
if (backStack != null) {
currentNavControllerBackStack = backStack.size();
}
}
}
if (isTaskRoot() && isBackStackEmpty && currentNavControllerBackStack == 2) {
finishAfterTransition(); finishAfterTransition();
return; return;
} }
@ -577,10 +586,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
private void showThread(@NonNull final Intent intent) { private void showThread(@NonNull final Intent intent) {
final String threadId = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_ID); final String threadId = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_ID);
final String threadTitle = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_TITLE); final String threadTitle = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_TITLE);
navigateToThread(threadId, threadTitle, null); navigateToThread(threadId, threadTitle);
} }
public void navigateToThread(final String threadId, final String threadTitle, final DirectThread backup) { public void navigateToThread(final String threadId, final String threadTitle) {
if (threadId == null || threadTitle == null) return; if (threadId == null || threadTitle == null) return;
currentNavControllerLiveData.observe(this, new Observer<NavController>() { currentNavControllerLiveData.observe(this, new Observer<NavController>() {
@Override @Override
@ -594,7 +603,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
// need handler.post() to wait for the fragment manager to be ready to navigate // need handler.post() to wait for the fragment manager to be ready to navigate
new Handler().post(() -> { new Handler().post(() -> {
final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections
.actionInboxToThread(threadId, threadTitle, backup); .actionInboxToThread(threadId, threadTitle);
navController.navigate(action); navController.navigate(action);
}); });
return; return;
@ -607,7 +616,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
@Nullable final Bundle arguments) { @Nullable final Bundle arguments) {
if (destination.getId() == R.id.directMessagesInboxFragment) { if (destination.getId() == R.id.directMessagesInboxFragment) {
final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections
.actionInboxToThread(threadId, threadTitle, backup); .actionInboxToThread(threadId, threadTitle);
controller.navigate(action); controller.navigate(action);
controller.removeOnDestinationChangedListener(this); controller.removeOnDestinationChangedListener(this);
} }

View File

@ -12,4 +12,7 @@ public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback
@Override @Override
public void onPlayerPause(final int position) {} public void onPlayerPause(final int position) {}
@Override
public void onPlayerRelease(final int position) {}
} }

View File

@ -148,5 +148,7 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
void onPlayerPlay(int position); void onPlayerPlay(int position);
void onPlayerPause(int position); void onPlayerPause(int position);
void onPlayerRelease(int position);
} }
} }

View File

@ -114,6 +114,13 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
sliderCallback.onPlayerPause(position); sliderCallback.onPlayerPause(position);
} }
} }
@Override
public void onRelease() {
if (sliderCallback != null) {
sliderCallback.onPlayerRelease(position);
}
}
}; };
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight(); final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
String videoUrl = null; String videoUrl = null;

View File

@ -15,4 +15,7 @@ public class VideoPlayerCallbackAdapter implements VideoPlayerViewHelper.VideoPl
@Override @Override
public void onPause() {} public void onPause() {}
@Override
public void onRelease() {}
} }

View File

@ -359,6 +359,9 @@ public class VideoPlayerViewHelper implements Player.EventListener {
// } // }
public void releasePlayer() { public void releasePlayer() {
if (videoPlayerCallback != null) {
videoPlayerCallback.onRelease();
}
if (player != null) { if (player != null) {
player.release(); player.release();
player = null; player = null;
@ -453,5 +456,7 @@ public class VideoPlayerViewHelper implements Player.EventListener {
void onPlay(); void onPlay();
void onPause(); void onPause();
void onRelease();
} }
} }

View File

@ -16,35 +16,6 @@ public class EmojiCategory {
public EmojiCategory(final EmojiCategoryType type) { public EmojiCategory(final EmojiCategoryType type) {
this.type = type; this.type = type;
switch (type) {
case SMILEYS_AND_EMOTION:
drawableRes = R.drawable.ic_round_emoji_emotions_24;
break;
case ANIMALS_AND_NATURE:
drawableRes = R.drawable.ic_round_emoji_nature_24;
break;
case FOOD_AND_DRINK:
drawableRes = R.drawable.ic_round_emoji_food_beverage_24;
break;
case TRAVEL_AND_PLACES:
drawableRes = R.drawable.ic_round_emoji_transportation_24;
break;
case ACTIVITIES:
drawableRes = R.drawable.ic_round_emoji_events_24;
break;
case OBJECTS:
drawableRes = R.drawable.ic_round_emoji_objects_24;
break;
case SYMBOLS:
drawableRes = R.drawable.ic_round_emoji_symbols_24;
break;
case FLAGS:
drawableRes = R.drawable.ic_round_emoji_flags_24;
break;
case OTHERS:
drawableRes = R.drawable.ic_round_unknown_24;
break;
}
} }
public EmojiCategoryType getType() { public EmojiCategoryType getType() {
@ -56,6 +27,37 @@ public class EmojiCategory {
} }
public int getDrawableRes() { public int getDrawableRes() {
if (drawableRes == 0) {
switch (type) {
case SMILEYS_AND_EMOTION:
drawableRes = R.drawable.ic_round_emoji_emotions_24;
break;
case ANIMALS_AND_NATURE:
drawableRes = R.drawable.ic_round_emoji_nature_24;
break;
case FOOD_AND_DRINK:
drawableRes = R.drawable.ic_round_emoji_food_beverage_24;
break;
case TRAVEL_AND_PLACES:
drawableRes = R.drawable.ic_round_emoji_transportation_24;
break;
case ACTIVITIES:
drawableRes = R.drawable.ic_round_emoji_events_24;
break;
case OBJECTS:
drawableRes = R.drawable.ic_round_emoji_objects_24;
break;
case SYMBOLS:
drawableRes = R.drawable.ic_round_emoji_symbols_24;
break;
case FLAGS:
drawableRes = R.drawable.ic_round_emoji_flags_24;
break;
case OTHERS:
drawableRes = R.drawable.ic_round_unknown_24;
break;
}
}
return drawableRes; return drawableRes;
} }

View File

@ -48,6 +48,7 @@ import androidx.core.content.PermissionChecker;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import androidx.core.widget.NestedScrollView; import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
@ -1062,15 +1063,28 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
@Override @Override
public void onPlayerPlay(final int position) { public void onPlayerPlay(final int position) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.enabledKeepScreenOn(activity);
if (!detailsVisible || hasBeenToggled) return; if (!detailsVisible || hasBeenToggled) return;
showPlayerControls(); showPlayerControls();
} }
@Override @Override
public void onPlayerPause(final int position) { public void onPlayerPause(final int position) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
if (detailsVisible || hasBeenToggled) return; if (detailsVisible || hasBeenToggled) return;
toggleDetails(); toggleDetails();
} }
@Override
public void onPlayerRelease(final int position) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
}
}); });
binding.sliderParent.setAdapter(sliderItemsAdapter); binding.sliderParent.setAdapter(sliderItemsAdapter);
if (sliderPosition >= 0 && sliderPosition < media.getCarouselMedia().size()) { if (sliderPosition >= 0 && sliderPosition < media.getCarouselMedia().size()) {
@ -1206,7 +1220,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
@Override @Override
public void onPlayerViewLoaded() { public void onPlayerViewLoaded() {
binding.playerControls.getRoot().setVisibility(View.VISIBLE); // binding.playerControls.getRoot().setVisibility(View.VISIBLE);
final ViewGroup.LayoutParams layoutParams = binding.videoPost.playerView.getLayoutParams(); final ViewGroup.LayoutParams layoutParams = binding.videoPost.playerView.getLayoutParams();
final int requiredWidth = Utils.displayMetrics.widthPixels; final int requiredWidth = Utils.displayMetrics.widthPixels;
final int resultingHeight = NumberUtils final int resultingHeight = NumberUtils
@ -1218,10 +1232,27 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
@Override @Override
public void onPlay() { public void onPlay() {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.enabledKeepScreenOn(activity);
if (detailsVisible) { if (detailsVisible) {
new Handler().postDelayed(() -> toggleDetails(), DETAILS_HIDE_DELAY_MILLIS); new Handler().postDelayed(() -> toggleDetails(), DETAILS_HIDE_DELAY_MILLIS);
} }
} }
@Override
public void onPause() {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
}
@Override
public void onRelease() {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
}
}; };
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight(); final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
String videoUrl = null; String videoUrl = null;

View File

@ -257,7 +257,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
navigating = true; navigating = true;
if (isAdded()) { if (isAdded()) {
final DirectMessageInboxFragmentDirections.ActionInboxToThread directions = DirectMessageInboxFragmentDirections final DirectMessageInboxFragmentDirections.ActionInboxToThread directions = DirectMessageInboxFragmentDirections
.actionInboxToThread(thread.getThreadId(), thread.getThreadTitle(), thread); .actionInboxToThread(thread.getThreadId(), thread.getThreadTitle());
NavHostFragment.findNavController(this).navigate(directions); NavHostFragment.findNavController(this).navigate(directions);
} }
navigating = false; navigating = false;

View File

@ -81,7 +81,6 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
final AppStateViewModel appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class); final AppStateViewModel appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
viewModel = new ViewModelProvider(this, new DirectSettingsViewModelFactory(fragmentActivity.getApplication(), viewModel = new ViewModelProvider(this, new DirectSettingsViewModelFactory(fragmentActivity.getApplication(),
args.getThreadId(), args.getThreadId(),
args.getBackup(),
args.getPending(), args.getPending(),
appStateViewModel.getCurrentUser())) appStateViewModel.getCurrentUser()))
.get(DirectSettingsViewModel.class); .get(DirectSettingsViewModel.class);
@ -348,15 +347,15 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
usersAdapter = new DirectUsersAdapter( usersAdapter = new DirectUsersAdapter(
inviter != null ? inviter.getPk() : -1, inviter != null ? inviter.getPk() : -1,
(position, user, selected) -> { (position, user, selected) -> {
if (!TextUtils.isEmpty(user.getFbId())) { if (TextUtils.isEmpty(user.getUsername()) && !TextUtils.isEmpty(user.getFbId())) {
Utils.openURL(context, "https://facebook.com/" + user.getFbId()); Utils.openURL(context, "https://facebook.com/" + user.getFbId());
return;
} }
else { if (TextUtils.isEmpty(user.getUsername())) return;
final ProfileNavGraphDirections.ActionGlobalProfileFragment directions = ProfileNavGraphDirections final ProfileNavGraphDirections.ActionGlobalProfileFragment directions = ProfileNavGraphDirections
.actionGlobalProfileFragment() .actionGlobalProfileFragment()
.setUsername("@" + user.getUsername()); .setUsername("@" + user.getUsername());
NavHostFragment.findNavController(this).navigate(directions); NavHostFragment.findNavController(this).navigate(directions);
}
}, },
(position, user) -> { (position, user) -> {
final ArrayList<Option<String>> options = viewModel.createUserOptions(user); final ArrayList<Option<String>> options = viewModel.createUserOptions(user);

View File

@ -100,6 +100,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient; import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.AppExecutors;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.DMUtils;
import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.PermissionUtils; import awais.instagrabber.utils.PermissionUtils;
import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.ResponseBodyUtils;
@ -317,6 +318,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
backStackSavedStateResultLiveData.postValue(null); backStackSavedStateResultLiveData.postValue(null);
}; };
private final MutableLiveData<Integer> inputLength = new MutableLiveData<>(0); private final MutableLiveData<Integer> inputLength = new MutableLiveData<>(0);
private MenuItem markAsSeenMenuItem;
@Override @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
@ -329,7 +331,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments); final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments);
viewModel = new ViewModelProvider(this, new DirectThreadViewModelFactory(fragmentActivity.getApplication(), viewModel = new ViewModelProvider(this, new DirectThreadViewModelFactory(fragmentActivity.getApplication(),
fragmentArgs.getThreadId(), fragmentArgs.getThreadId(),
fragmentArgs.getBackup(),
fragmentArgs.getPending(), fragmentArgs.getPending(),
appStateViewModel.getCurrentUser())) appStateViewModel.getCurrentUser()))
.get(DirectThreadViewModel.class); .get(DirectThreadViewModel.class);
@ -368,9 +369,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
@Override @Override
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
inflater.inflate(R.menu.dm_thread_menu, menu); inflater.inflate(R.menu.dm_thread_menu, menu);
final MenuItem markAsSeenMenuItem = menu.findItem(R.id.mark_as_seen); markAsSeenMenuItem = menu.findItem(R.id.mark_as_seen);
if (markAsSeenMenuItem != null) { if (markAsSeenMenuItem != null) {
markAsSeenMenuItem.setVisible(false); if (autoMarkAsSeen) {
markAsSeenMenuItem.setVisible(false);
} else {
markAsSeenMenuItem.setEnabled(false);
}
} }
} }
@ -379,15 +384,14 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
final int itemId = item.getItemId(); final int itemId = item.getItemId();
if (itemId == R.id.info) { if (itemId == R.id.info) {
final DirectMessageThreadFragmentDirections.ActionThreadToSettings directions = DirectMessageThreadFragmentDirections final DirectMessageThreadFragmentDirections.ActionThreadToSettings directions = DirectMessageThreadFragmentDirections
.actionThreadToSettings(viewModel.getThreadId(), null, null); .actionThreadToSettings(viewModel.getThreadId(), null);
final Boolean pending = viewModel.isPending().getValue(); final Boolean pending = viewModel.isPending().getValue();
directions.setPending(pending == null ? false : pending); directions.setPending(pending == null ? false : pending);
NavHostFragment.findNavController(this).navigate(directions); NavHostFragment.findNavController(this).navigate(directions);
return true; return true;
} }
if (itemId == R.id.mark_as_seen) { if (itemId == R.id.mark_as_seen) {
// new ThreadAction().execute("seen", lastMessage); handleMarkAsSeen(item);
item.setVisible(false);
return true; return true;
} }
if (itemId == R.id.refresh && viewModel != null) { if (itemId == R.id.refresh && viewModel != null) {
@ -397,6 +401,40 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
private void handleMarkAsSeen(@NonNull final MenuItem item) {
final LiveData<Resource<Object>> resourceLiveData = viewModel.markAsSeen();
resourceLiveData.observe(getViewLifecycleOwner(), new Observer<Resource<Object>>() {
@Override
public void onChanged(final Resource<Object> resource) {
try {
if (resource == null) return;
final Context context = getContext();
if (context == null) return;
switch (resource.status) {
case SUCCESS:
Toast.makeText(context, R.string.marked_as_seen, Toast.LENGTH_SHORT).show();
case LOADING:
item.setEnabled(false);
break;
case ERROR:
item.setEnabled(true);
if (resource.message != null) {
Snackbar.make(context, binding.getRoot(), resource.message, Snackbar.LENGTH_LONG).show();
return;
}
if (resource.resId != 0) {
Snackbar.make(binding.getRoot(), resource.resId, Snackbar.LENGTH_LONG).show();
return;
}
break;
}
} finally {
resourceLiveData.removeObserver(this);
}
}
});
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
@ -464,6 +502,12 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
cleanup(); cleanup();
} }
@Override
public void onDestroy() {
viewModel.deleteThreadIfRequired();
super.onDestroy();
}
@SuppressLint("UnsafeExperimentalUsageError") @SuppressLint("UnsafeExperimentalUsageError")
private void cleanup() { private void cleanup() {
if (prevTitleRunnable != null) { if (prevTitleRunnable != null) {
@ -903,9 +947,15 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
} }
private void submitItemsToAdapter(final List<DirectItem> items) { private void submitItemsToAdapter(final List<DirectItem> items) {
if (autoMarkAsSeen) { binding.chats.post(() -> {
binding.chats.post(() -> viewModel.markAsSeen()); if (autoMarkAsSeen) {
} viewModel.markAsSeen();
return;
}
final DirectThread thread = threadLiveData.getValue();
if (thread == null) return;
markAsSeenMenuItem.setEnabled(!DMUtils.isRead(thread));
});
if (itemsAdapter == null) return; if (itemsAdapter == null) return;
itemsAdapter.submitList(items, () -> { itemsAdapter.submitList(items, () -> {
itemOrHeaders = itemsAdapter.getList(); itemOrHeaders = itemsAdapter.getList();

View File

@ -163,7 +163,7 @@ public class DirectPendingInboxFragment extends Fragment implements SwipeRefresh
navigating = true; navigating = true;
if (isAdded()) { if (isAdded()) {
final DirectPendingInboxFragmentDirections.ActionPendingInboxToThread directions = DirectPendingInboxFragmentDirections final DirectPendingInboxFragmentDirections.ActionPendingInboxToThread directions = DirectPendingInboxFragmentDirections
.actionPendingInboxToThread(thread.getThreadId(), thread.getThreadTitle(), thread); .actionPendingInboxToThread(thread.getThreadId(), thread.getThreadTitle());
directions.setPending(true); directions.setPending(true);
NavHostFragment.findNavController(this).navigate(directions); NavHostFragment.findNavController(this).navigate(directions);
} }

View File

@ -74,6 +74,8 @@ import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
import awais.instagrabber.dialogs.ProfilePicDialogFragment; import awais.instagrabber.dialogs.ProfilePicDialogFragment;
import awais.instagrabber.fragments.PostViewV2Fragment; import awais.instagrabber.fragments.PostViewV2Fragment;
import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.managers.InboxManager;
import awais.instagrabber.models.HighlightModel; import awais.instagrabber.models.HighlightModel;
import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.PostsLayoutPreferences;
import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.StoryModel;
@ -590,8 +592,11 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private void fetchProfileDetails() { private void fetchProfileDetails() {
accountIsUpdated = false; accountIsUpdated = false;
new ProfileFetcher(TextUtils.isEmpty(username) ? null : username.trim().substring(1), String usernameTemp = username.trim();
myId, isLoggedIn, new FetchListener<User>() { if (usernameTemp.startsWith("@")) {
usernameTemp = usernameTemp.substring(1);
}
new ProfileFetcher(TextUtils.isEmpty(username) ? null : usernameTemp, myId, isLoggedIn, new FetchListener<User>() {
@Override @Override
public void onResult(final User user) { public void onResult(final User user) {
if (getContext() == null) return; if (getContext() == null) return;
@ -612,7 +617,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
isLoggedIn ? R.string.error_loading_profile_loggedin : R.string.error_loading_profile, isLoggedIn ? R.string.error_loading_profile_loggedin : R.string.error_loading_profile,
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
} catch (final Throwable e) {} } catch (final Throwable ignored) {}
} }
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ -1073,7 +1078,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
profileDetailsBinding.btnDM.setEnabled(true); profileDetailsBinding.btnDM.setEnabled(true);
return; return;
} }
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername(), thread); final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
if (!inboxManager.containsThread(thread.getThreadId())) {
thread.setTemp(true);
inboxManager.addThread(thread, 0);
}
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
profileDetailsBinding.btnDM.setEnabled(true); profileDetailsBinding.btnDM.setEnabled(true);
}).execute(); }).execute();
}); });

View File

@ -74,9 +74,8 @@ public final class DirectMessagesManager {
public ThreadManager getThreadManager(@NonNull final String threadId, public ThreadManager getThreadManager(@NonNull final String threadId,
final boolean pending, final boolean pending,
final DirectThread backup,
@NonNull final User currentUser, @NonNull final User currentUser,
@NonNull final ContentResolver contentResolver) { @NonNull final ContentResolver contentResolver) {
return ThreadManager.getInstance(threadId, pending, backup, currentUser, contentResolver); return ThreadManager.getInstance(threadId, pending, currentUser, contentResolver);
} }
} }

View File

@ -18,6 +18,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -357,4 +358,15 @@ public final class InboxManager {
public void setPendingRequestsTotal(final int total) { public void setPendingRequestsTotal(final int total) {
pendingRequestsTotal.postValue(total); pendingRequestsTotal.postValue(total);
} }
public boolean containsThread(final String threadId) {
if (threadId == null) return false;
synchronized (this.inbox) {
final DirectInbox currentDirectInbox = getCurrentDirectInbox();
if (currentDirectInbox == null) return false;
final List<DirectThread> threads = currentDirectInbox.getThreads();
if (threads == null) return false;
return threads.stream().anyMatch(thread -> Objects.equals(thread.getThreadId(), threadId));
}
}
} }

View File

@ -123,7 +123,6 @@ public final class ThreadManager {
public static ThreadManager getInstance(@NonNull final String threadId, public static ThreadManager getInstance(@NonNull final String threadId,
final boolean pending, final boolean pending,
final DirectThread backup,
@NonNull final User currentUser, @NonNull final User currentUser,
@NonNull final ContentResolver contentResolver) { @NonNull final ContentResolver contentResolver) {
ThreadManager instance = INSTANCE_MAP.get(threadId); ThreadManager instance = INSTANCE_MAP.get(threadId);
@ -131,7 +130,7 @@ public final class ThreadManager {
synchronized (LOCK) { synchronized (LOCK) {
instance = INSTANCE_MAP.get(threadId); instance = INSTANCE_MAP.get(threadId);
if (instance == null) { if (instance == null) {
instance = new ThreadManager(threadId, pending, backup, currentUser, contentResolver); instance = new ThreadManager(threadId, pending, currentUser, contentResolver);
INSTANCE_MAP.put(threadId, instance); INSTANCE_MAP.put(threadId, instance);
} }
} }
@ -145,7 +144,6 @@ public final class ThreadManager {
private ThreadManager(@NonNull final String threadId, private ThreadManager(@NonNull final String threadId,
final boolean pending, final boolean pending,
final DirectThread backup,
@NonNull final User currentUser, @NonNull final User currentUser,
@NonNull final ContentResolver contentResolver) { @NonNull final ContentResolver contentResolver) {
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance(); final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
@ -164,17 +162,17 @@ public final class ThreadManager {
service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid); service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId); mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId);
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, viewerId); friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, viewerId);
setupTransformations(backup); setupTransformations();
// fetchChats(); // fetchChats();
} }
public void moveFromPending() { public void moveFromPending() {
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance(); final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
this.inboxManager = messagesManager.getInboxManager(); this.inboxManager = messagesManager.getInboxManager();
setupTransformations(null); setupTransformations();
} }
private void setupTransformations(final DirectThread backup) { private void setupTransformations() {
// Transformations // Transformations
thread = distinctUntilChanged(map(inboxManager.getInbox(), inboxResource -> { thread = distinctUntilChanged(map(inboxManager.getInbox(), inboxResource -> {
if (inboxResource == null) { if (inboxResource == null) {
@ -188,7 +186,7 @@ public final class ThreadManager {
final DirectThread thread = threads.stream() final DirectThread thread = threads.stream()
.filter(t -> t.getThreadId().equals(threadId)) .filter(t -> t.getThreadId().equals(threadId))
.findFirst() .findFirst()
.orElse(backup); .orElse(null);
if (thread != null) { if (thread != null) {
cursor = thread.getOldestCursor(); cursor = thread.getOldestCursor();
hasOlder = thread.hasOlder(); hasOlder = thread.hasOlder();
@ -1799,18 +1797,23 @@ public final class ThreadManager {
return inviter; return inviter;
} }
public void markAsSeen(@NonNull final DirectItem directItem) { public LiveData<Resource<Object>> markAsSeen(@NonNull final DirectItem directItem) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
final Call<DirectItemSeenResponse> request = service.markAsSeen(threadId, directItem); final Call<DirectItemSeenResponse> request = service.markAsSeen(threadId, directItem);
request.enqueue(new Callback<DirectItemSeenResponse>() { request.enqueue(new Callback<DirectItemSeenResponse>() {
@Override @Override
public void onResponse(@NonNull final Call<DirectItemSeenResponse> call, public void onResponse(@NonNull final Call<DirectItemSeenResponse> call,
@NonNull final Response<DirectItemSeenResponse> response) { @NonNull final Response<DirectItemSeenResponse> response) {
if (!response.isSuccessful()) { if (!response.isSuccessful()) {
handleErrorBody(call, response, null); handleErrorBody(call, response, data);
return; return;
} }
final DirectItemSeenResponse seenResponse = response.body(); final DirectItemSeenResponse seenResponse = response.body();
if (seenResponse == null) return; if (seenResponse == null) {
data.postValue(Resource.error(R.string.generic_null_response, null));
return;
}
inboxManager.fetchUnseenCount(); inboxManager.fetchUnseenCount();
final DirectItemSeenResponsePayload payload = seenResponse.getPayload(); final DirectItemSeenResponsePayload payload = seenResponse.getPayload();
if (payload == null) return; if (payload == null) return;
@ -1822,14 +1825,17 @@ public final class ThreadManager {
lastSeenAt.put(currentUser.getPk(), new DirectThreadLastSeenAt(timestamp, directItem.getItemId())); lastSeenAt.put(currentUser.getPk(), new DirectThreadLastSeenAt(timestamp, directItem.getItemId()));
thread.setLastSeenAt(lastSeenAt); thread.setLastSeenAt(lastSeenAt);
setThread(thread, true); setThread(thread, true);
data.postValue(Resource.success(new Object()));
} }
@Override @Override
public void onFailure(@NonNull final Call<DirectItemSeenResponse> call, public void onFailure(@NonNull final Call<DirectItemSeenResponse> call,
@NonNull final Throwable t) { @NonNull final Throwable t) {
Log.e(TAG, "onFailure: ", t); Log.e(TAG, "onFailure: ", t);
data.postValue(Resource.error(t.getMessage(), null));
} }
}); });
return data;
} }
private interface OnSuccessAction { private interface OnSuccessAction {

View File

@ -45,6 +45,7 @@ public class DirectThread implements Serializable, Cloneable {
private boolean approvalRequiredForNewMembers; private boolean approvalRequiredForNewMembers;
private int inputMode; private int inputMode;
private final List<ThreadContext> threadContextItems; private final List<ThreadContext> threadContextItems;
private boolean isTemp;
public DirectThread(final String threadId, public DirectThread(final String threadId,
final String threadV2Id, final String threadV2Id,
@ -292,6 +293,14 @@ public class DirectThread implements Serializable, Cloneable {
return threadContextItems; return threadContextItems;
} }
public boolean isTemp() {
return isTemp;
}
public void setTemp(final boolean isTemp) {
this.isTemp = isTemp;
}
@Nullable @Nullable
public DirectItem getFirstDirectItem() { public DirectItem getFirstDirectItem() {
DirectItem firstItem = null; DirectItem firstItem = null;

View File

@ -359,4 +359,16 @@ public final class Utils {
} }
return drawable; return drawable;
} }
public static void enabledKeepScreenOn(@NonNull final Activity activity) {
final Window window = activity.getWindow();
if (window == null) return;
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
public static void disableKeepScreenOn(@NonNull final Activity activity) {
final Window window = activity.getWindow();
if (window == null) return;
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
} }

View File

@ -2,27 +2,25 @@ package awais.instagrabber.utils.emoji;
import android.util.Log; import android.util.Log;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.ibm.icu.impl.Utility; import com.google.gson.Gson;
import com.ibm.icu.lang.CharSequences; import com.google.gson.reflect.TypeToken;
import com.ibm.icu.text.UnicodeSet;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import awais.instagrabber.customviews.emoji.Emoji; import awais.instagrabber.customviews.emoji.Emoji;
import awais.instagrabber.customviews.emoji.EmojiCategory; import awais.instagrabber.customviews.emoji.EmojiCategory;
import awais.instagrabber.customviews.emoji.EmojiCategoryType; import awais.instagrabber.customviews.emoji.EmojiCategoryType;
import awais.instagrabber.utils.NetworkUtils;
public final class EmojiParser { public final class EmojiParser {
private static final String TAG = EmojiParser.class.getSimpleName(); private static final String TAG = EmojiParser.class.getSimpleName();
@ -30,51 +28,8 @@ public final class EmojiParser {
private static EmojiParser instance; private static EmojiParser instance;
// private static final String COMBINING_ENCLOSING_KEYCAP = "\u20E3"; private Map<String, Emoji> allEmojis = Collections.emptyMap();
// private static final String ZWJ = "\u200D"; private Map<EmojiCategoryType, EmojiCategory> categoryMap = Collections.emptyMap();
// private static final UnicodeSet REGIONAL_INDICATORS = new UnicodeSet(0x1F1E6, 0x1F1FF).freeze();
// private static final UnicodeSet TAGS = new UnicodeSet(0xE0000, 0xE007F).freeze();
// private static final UnicodeSet FAMILY = new UnicodeSet("[\u200D 👦-👩 💋 ❤]").freeze();
// private static final UnicodeSet GENDER = new UnicodeSet().add(0x2640).add(0x2642).freeze();
// private static final UnicodeSet SPECIALS = new UnicodeSet("["
// + "{🐈‍⬛}{🐻‍❄}{👨‍🍼}{👩‍🍼}{🧑‍🍼}{🧑‍🎄}{🧑‍🤝‍🧑}{🏳‍🌈} {👁‍🗨} {🏴‍☠} {🐕‍🦺} {👨‍🦯} {👨‍🦼} {👨‍🦽} {👩‍🦯} {👩‍🦼} {👩‍🦽}"
// + "{🏳‍⚧}{🧑‍⚕}{🧑‍⚖}{🧑‍✈}{🧑‍🌾}{🧑‍🍳}{🧑‍🎓}{🧑‍🎤}{🧑‍🎨}{🧑‍🏫}{🧑‍🏭}{🧑‍💻}{🧑‍💼}{🧑‍🔧}{🧑‍🔬}{🧑‍🚀}{🧑‍🚒}{🧑‍🦯}{🧑‍🦼}{🧑‍🦽}"
// + "{❤‍🔥}, {❤‍🩹}, {😮‍💨}, {😵‍💫}" // #E13.1
// + "]").freeze();
// May have to add from above, if there is a failure in testAnnotationPaths. Failure will be like:
// got java.util.TreeSet<[//ldml/annotations/annotation[@cp="🏳‍⚧"][@type="tts"], //ldml/annotations/annotation[@cp="🧑‍⚕"][@type="tts"], ...
// just extract the items in "...", and change into {...} for adding above.
// Example: //ldml/annotations/annotation[@cp="🧑‍⚕"] ==> {🧑}
// private static final UnicodeSet MAN_WOMAN = new UnicodeSet("[👨 👩]").freeze();
// private static final UnicodeSet OBJECT = new UnicodeSet("[👩 🎓 🌾 🍳 🏫 🏭 🎨 🚒 ✈ 🚀 🎤 💻 🔬 💼 🔧 ⚖ ⚕]").freeze();
// private static final String TYPE_TTS = "[@type=\"tts\"]";
private static final String EMOJI_VARIANT = "\uFE0F";
private static final UnicodeSet SKIN_TONE_MODIFIERS = new UnicodeSet("[🏻-🏿]").freeze();
private static final String SKIN_TONE_PATTERN = SKIN_TONE_MODIFIERS.toPattern(true);
private static final Map<EmojiCategoryType, EmojiCategory> CATEGORY_MAP = new LinkedHashMap<>();
private static final Map<String, Emoji> ALL_EMOJIS = new HashMap<>();
// private final UnicodeMap<String> emojiToMajorCategory = new UnicodeMap<>();
// private final UnicodeMap<String> emojiToMinorCategory = new UnicodeMap<>();
// private final UnicodeMap<String> toName = new UnicodeMap<>();
// /**
// * A mapping from a majorCategory to a unique ordering number, based on the first time it is encountered.
// */
// private final Map<String, Long> majorToOrder = new HashMap<>();
// private final List<String> majorToOrder = new LinkedList<String>();
// /**
// * A mapping from a minorCategory to a unique ordering number, based on the first time it is encountered.
// */
// private final Map<String, Long> minorToOrder = new HashMap<>();
// private final Map<String, Long> emojiToOrder = new LinkedHashMap<>();
// private final UnicodeSet nonConstructed = new UnicodeSet();
// private final UnicodeSet allRgi = new UnicodeSet();
// private final UnicodeSet allRgiNoES = new UnicodeSet();
// private final UnicodeMap<String> EXTRA_SYMBOL_MINOR_CATEGORIES = new UnicodeMap<>();
// private final Map<String, Long> EXTRA_SYMBOL_ORDER;
// private final boolean DEBUG = false;
// private Set<String> NAME_PATHS = null;
// private Set<String> KEYWORD_PATHS = null;
private ImmutableList<EmojiCategory> categories; private ImmutableList<EmojiCategory> categories;
public static EmojiParser getInstance() { public static EmojiParser getInstance() {
@ -89,267 +44,56 @@ public final class EmojiParser {
} }
private EmojiParser() { private EmojiParser() {
// Log.d(TAG, "Emoji: " + new Date()); final String file = "res/raw/emojis.json";
// String[][] data = {
// {"arrow", "→ ↓ ↑ ← ↔ ↕ ⇆ ⇅"},
// {"alphanum", "© ® ℗ ™ µ"},
// {"geometric", "▼ ▶ ▲ ◀ ● ○ ◯ ◊"},
// {"math", "× ÷ √ ∞ ∆ ∇ ⁻ ¹ ² ³ ≡ ∈ ⊂ ∩ ° + ± = ≈ ≠ > < ≤ ≥ ¬ | ~"},
// {"punctuation", "§ † ‡ \\u0020 , 、 ، ; : ؛ ! ¡ ? ¿ ؟ ¶ ※ / \\ & # % ‰ ″ ‴ @ * ♪ ♭ ♯ ` ´ ^ ¨ ― _ - — • · . … 。 ‧ ・ ' “ ” „ » « ( ) [ ] { } 〈 〉 《 》 「 」 『 』 〖 〗 【 】"},
// {"currency", "€ £ ¥ ₹ ₽ $ ¢ ฿ ₪ ₺ ₫ ₱ ₩ ₡ ₦ ₮ ৳ ₴ ₸ ₲ ₵ ៛ ₭ ֏ ₥ ₾ ₼ ₿ ؋"},
// {"other-symbol", "‾‽‸⁂↚↛↮↙↜↝↞↟↠↡↢↣↤↥↦↧↨↫↬↭↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇇⇈⇉⇊⇋⇌⇐⇍⇑⇒⇏⇓⇔⇎⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇵∀∂∃∅∉∋∎∏∑≮≯∓∕⁄∗∘∙∝∟∠∣∥∧∫∬∮∴∵∶∷∼∽∾≃≅≌≒≖≣≦≧≪≫≬≳≺≻⊁⊃⊆⊇⊕⊖⊗⊘⊙⊚⊛⊞⊟⊥⊮⊰⊱⋭⊶⊹⊿⋁⋂⋃⋅⋆⋈⋒⋘⋙⋮⋯⋰⋱■□▢▣▤▥▦▧▨▩▬▭▮▰△▴▵▷▸▹►▻▽▾▿◁◂◃◄◅◆◇◈◉◌◍◎◐◑◒◓◔◕◖◗◘◙◜◝◞◟◠◡◢◣◤◥◦◳◷◻◽◿⨧⨯⨼⩣⩽⪍⪚⪺₢₣₤₰₳₶₷₨﷼"},
// };
// get the maximum suborder for each subcategory
// Map<String, Long> subcategoryToMaxSuborder = new HashMap<>();
// for (String[] row : data) {
// final String subcategory = row[0];
// for (Entry<String, String> entry : emojiToMinorCategory.entrySet()) {
// if (entry.getValue().equals(subcategory)) {
// String emoji = entry.getKey();
// Long order = emojiToOrder.get(emoji);
// Long currentMax = subcategoryToMaxSuborder.get(subcategory);
// if (order == null) continue;
// if (currentMax == null || currentMax < order) {
// subcategoryToMaxSuborder.put(subcategory, order);
// }
// }
// }
// }
// if (DEBUG) System.out.println(subcategoryToMaxSuborder);
// Map<String, Long> _EXTRA_SYMBOL_ORDER = new LinkedHashMap<>();
// for (String[] row : data) {
// final String subcategory = row[0];
// final String characters = row[1];
//
// List<String> items = new ArrayList<>();
// for (int cp : With.codePointArray(characters)) {
// if (cp != ' ') {
// items.add(With.fromCodePoint(cp));
// }
// }
// final UnicodeSet uset = new UnicodeSet().addAll(items);
// if (uset.containsSome(EXTRA_SYMBOL_MINOR_CATEGORIES.keySet())) {
// throw new IllegalArgumentException("Duplicate values in " + EXTRA_SYMBOL_MINOR_CATEGORIES);
// }
// EXTRA_SYMBOL_MINOR_CATEGORIES.putAll(uset, subcategory);
// final Long countObject = subcategoryToMaxSuborder.get(subcategory);
// if (countObject == null) continue;
// long count = countObject;
// for (String s : items) {
// ++count;
// _EXTRA_SYMBOL_ORDER.put(s, count);
// }
// subcategoryToMaxSuborder.put(subcategory, count);
// }
// if (DEBUG) System.out.println(_EXTRA_SYMBOL_ORDER);
// EXTRA_SYMBOL_MINOR_CATEGORIES.freeze();
// EXTRA_SYMBOL_ORDER = ImmutableMap.copyOf(_EXTRA_SYMBOL_ORDER);
/*
# group: Smileys & People
# subgroup: face-positive
1F600 ; fully-qualified # 😀 grinning face
*/
final Splitter semi = Splitter.on(CharMatcher.anyOf(";#")).trimResults();
String majorCategory;
final String file = "res/raw/emoji_test.txt";
final ClassLoader classLoader = getClass().getClassLoader(); final ClassLoader classLoader = getClass().getClassLoader();
if (classLoader == null) { if (classLoader == null) {
Log.e(TAG, "Emoji: classLoader is null"); Log.e(TAG, "Emoji: classLoader is null");
return; return;
} }
try (final InputStream in = classLoader.getResourceAsStream(file); try (final InputStream in = classLoader.getResourceAsStream(file)) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { final String json = NetworkUtils.readFromInputStream(in);
String line; final Gson gson = new Gson();
EmojiCategoryType categoryType = null; final Type type = new TypeToken<Map<EmojiCategoryType, EmojiCategory>>() {}.getType();
while ((line = reader.readLine()) != null) { categoryMap = gson.fromJson(json, type);
if (line.startsWith("#")) { // Log.d(TAG, "EmojiParser: " + categoryMap);
line = line.substring(1).trim(); allEmojis = categoryMap.values()
if (line.startsWith("group:")) { .stream()
majorCategory = line.substring("group:".length()).trim(); .flatMap((Function<EmojiCategory, Stream<Emoji>>) emojiCategory -> {
if (!majorCategory.equals("Component")) { // Skip Component final Map<String, Emoji> emojis = emojiCategory.getEmojis();
if (majorCategory.equals("Smileys & Emotion") || majorCategory.equals("People & Body")) { return emojis.values().stream();
// Put 'People & Body' in 'Smileys & Emotion' category })
categoryType = EmojiCategoryType.SMILEYS_AND_EMOTION; .flatMap(emoji -> ImmutableList.<Emoji>builder()
} else { .add(emoji)
categoryType = EmojiCategoryType.valueOfName(majorCategory); .addAll(emoji.getVariants())
} .build()
final boolean contains = CATEGORY_MAP.containsKey(categoryType); .stream())
if (!contains) { .collect(Collectors.toMap(Emoji::getUnicode, Function.identity()));
CATEGORY_MAP.put(categoryType, new EmojiCategory(categoryType));
}
}
}
continue;
}
if (categoryType == null) continue;
line = line.trim();
if (line.isEmpty()) {
continue;
}
final Iterator<String> it = semi.split(line).iterator();
String emojiHex = it.next();
String original = Utility.fromHex(emojiHex, 4, " ");
String status = it.next();
if (!status.startsWith("fully-qualified")) { // only use fully qualified
continue;
}
final EmojiCategory emojiCategory = CATEGORY_MAP.get(categoryType);
final Map<String, Emoji> emojis = emojiCategory == null ? new LinkedHashMap<>() : emojiCategory.getEmojis();
String comment = it.next();
// The comment is now of the form: # 😁 E0.6 beaming face with smiling eyes
int spacePos = comment.indexOf(' ');
spacePos = comment.indexOf(' ', spacePos + 1); // get second space
final String name = comment.substring(spacePos + 1).trim();
final Emoji emoji = new Emoji(original, name);
ALL_EMOJIS.put(original, emoji);
String minimal = original.replace(EMOJI_VARIANT, "");
//noinspection deprecation
boolean singleton = CharSequences.getSingleCodePoint(minimal) != Integer.MAX_VALUE;
if (!singleton && SKIN_TONE_MODIFIERS.containsSome(minimal)) {
// skin tone variant
final String parent = minimal.replaceAll(SKIN_TONE_PATTERN, "");
final Emoji parentEmoji = emojis.get(parent);
if (parentEmoji != null) {
parentEmoji.addVariant(emoji);
}
continue;
}
emojis.put(original, emoji);
// skip constructed values
// if (minimal.contains(COMBINING_ENCLOSING_KEYCAP)
// || REGIONAL_INDICATORS.containsSome(minimal)
// || TAGS.containsSome(minimal)
// || !singleton && MODIFIERS.containsSome(minimal)
// || !singleton && FAMILY.containsAll(minimal)) {
// // do nothing
// } else if (minimal.contains(ZWJ)) { // only do certain ZWJ sequences
// if (SPECIALS.contains(minimal)
// || GENDER.containsSome(minimal)
// || MAN_WOMAN.contains(minimal.codePointAt(0)) && OBJECT.contains(minimal.codePointBefore(minimal.length()))) {
// // nonConstructed.add(minimal);
// }
// } else if (!minimal.contains("🔟")) {
// // nonConstructed.add(minimal);
// }
}
// for (Entry<Pair<Integer,Integer>, String> entry : majorPlusMinorToEmoji.entries()) {
// String minimal = entry.getValue();
// emojiToOrder.put(minimal, emojiToOrder.size());
// }
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Emoji: ", e); Log.e(TAG, "EmojiParser: ", e);
} }
} }
// private static <K, V> void putUnique(Map<K, V> map, K key, V value) {
// V oldValue = map.put(key, value);
// if (oldValue != null) {
// throw new ICUException("Attempt to change value of " + map
// + " for " + key
// + " from " + oldValue
// + " to " + value
// );
// }
// }
public Map<EmojiCategoryType, EmojiCategory> getCategoryMap() { public Map<EmojiCategoryType, EmojiCategory> getCategoryMap() {
return CATEGORY_MAP; return categoryMap;
} }
public List<EmojiCategory> getEmojiCategories() { public List<EmojiCategory> getEmojiCategories() {
if (categories == null) { if (categories == null) {
final Collection<EmojiCategory> categoryCollection = CATEGORY_MAP.values(); final Collection<EmojiCategory> categoryCollection = categoryMap.values();
categories = ImmutableList.copyOf(categoryCollection); categories = ImmutableList.copyOf(categoryCollection);
} }
return categories; return categories;
} }
public Map<String, Emoji> getAllEmojis() { public Map<String, Emoji> getAllEmojis() {
return ALL_EMOJIS; return allEmojis;
} }
public Emoji getEmoji(final String emoji) { public Emoji getEmoji(final String emoji) {
if (emoji == null) { if (emoji == null) {
return null; return null;
} }
return ALL_EMOJIS.get(emoji); return allEmojis.get(emoji);
} }
// public String getMinorCategory(String emoji) {
// String minorCat = emojiToMinorCategory.get(emoji);
// if (minorCat == null) {
// minorCat = EXTRA_SYMBOL_MINOR_CATEGORIES.get(emoji);
// if (minorCat == null) {
// throw new InternalCldrException("No minor category (aka subgroup) found for " + emoji
// + ". Update emoji-test.txt to latest, and setValue PathHeader.. functionMap.put(\"minor\", ...");
// }
// }
// return minorCat;
// }
// public long getEmojiToOrder(String emoji) {
// Long result = emojiToOrder.get(emoji);
// if (result == null) {
// result = EXTRA_SYMBOL_ORDER.get(emoji);
// if (result == null) {
// throw new InternalCldrException("No Order found for " + emoji
// + ". Update emoji-test.txt to latest, and setValue PathHeader.. functionMap.put(\"minor\", ...");
// }
// }
// return result;
// }
// public long getEmojiMinorOrder(String minor) {
// Long result = minorToOrder.get(minor);
// if (result == null) {
// throw new InternalCldrException("No minor category (aka subgroup) found for " + minor
// + ". Update emoji-test.txt to latest, and setValue PathHeader.. functionMap.put(\"minor\", ...");
// }
// return result;
// }
// public String getMajorCategory(String emoji) {
// String majorCat = emojiToMajorCategory.get(emoji);
// if (majorCat == null) {
// if (EXTRA_SYMBOL_MINOR_CATEGORIES.containsKey(emoji)) {
// majorCat = "Symbols";
// } else {
// throw new InternalCldrException("No minor category (aka subgroup) found for " + emoji
// + ". Update emoji-test.txt to latest, and setValue PathHeader.. functionMap.put(\"major\", ...");
// }
// }
// return majorCat;
// }
// public Set<String> getMinorCategoriesWithExtras() {
// Set<String> result = new LinkedHashSet<>(emojiToMinorCategory.values());
// result.addAll(EXTRA_SYMBOL_MINOR_CATEGORIES.getAvailableValues());
// return ImmutableSet.copyOf(result);
// }
// public UnicodeSet getEmojiInMinorCategoriesWithExtras(String minorCategory) {
// return new UnicodeSet(emojiToMinorCategory.getSet(minorCategory))
// .addAll(EXTRA_SYMBOL_MINOR_CATEGORIES.getSet(minorCategory))
// .freeze();
// }
// public synchronized Set<String> getNamePaths() {
// return NAME_PATHS != null ? NAME_PATHS : (NAME_PATHS = buildPaths(TYPE_TTS));
// }
// public synchronized Set<String> getKeywordPaths() {
// return KEYWORD_PATHS != null ? KEYWORD_PATHS : (KEYWORD_PATHS = buildPaths(""));
// }
// private ImmutableSet<String> buildPaths(String suffix) {
// ImmutableSet.Builder<String> builder = ImmutableSet.builder();
// for (String s : getNonConstructed()) {
// String base = "//ldml/annotations/annotation[@cp=\"" + s + "\"]" + suffix;
// builder.add(base);
// }
// return builder.build();
// }
} }

View File

@ -1,50 +0,0 @@
package awais.instagrabber.utils.emoji;
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
/*
*******************************************************************************
* Copyright (C) 2009-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
import java.util.Map;
/**
* @author markdavis
*/
public class ImmutableEntry<K, V> implements Map.Entry<K, V> {
final K k;
final V v;
ImmutableEntry(K key, V value) {
k = key;
v = value;
}
public K getKey() {return k;}
public V getValue() {return v;}
public V setValue(V value) {
throw new UnsupportedOperationException();
}
public boolean equals(Object o) {
try {
Map.Entry e = (Map.Entry) o;
return UnicodeMap.areEqual(e.getKey(), k) && UnicodeMap.areEqual(e.getValue(), v);
} catch (ClassCastException e) {
return false;
}
}
public int hashCode() {
return ((k == null ? 0 : k.hashCode()) ^ (v == null ? 0 : v.hashCode()));
}
public String toString() {
return k + "=" + v;
}
}

View File

@ -45,7 +45,6 @@ public class DirectSettingsViewModel extends AndroidViewModel {
public DirectSettingsViewModel(final Application application, public DirectSettingsViewModel(final Application application,
@NonNull final String threadId, @NonNull final String threadId,
final DirectThread backup,
final boolean pending, final boolean pending,
@NonNull final User currentUser) { @NonNull final User currentUser) {
super(application); super(application);
@ -59,7 +58,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
final ContentResolver contentResolver = application.getContentResolver(); final ContentResolver contentResolver = application.getContentResolver();
resources = getApplication().getResources(); resources = getApplication().getResources();
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance(); final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
threadManager = messagesManager.getThreadManager(threadId, pending, backup, currentUser, contentResolver); threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
} }
@NonNull @NonNull

View File

@ -23,6 +23,7 @@ import java.util.stream.Collectors;
import awais.instagrabber.customviews.emoji.Emoji; import awais.instagrabber.customviews.emoji.Emoji;
import awais.instagrabber.managers.DirectMessagesManager; import awais.instagrabber.managers.DirectMessagesManager;
import awais.instagrabber.managers.InboxManager;
import awais.instagrabber.managers.ThreadManager; import awais.instagrabber.managers.ThreadManager;
import awais.instagrabber.models.Resource; import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
@ -57,7 +58,6 @@ public class DirectThreadViewModel extends AndroidViewModel {
public DirectThreadViewModel(@NonNull final Application application, public DirectThreadViewModel(@NonNull final Application application,
@NonNull final String threadId, @NonNull final String threadId,
final DirectThread backup,
final boolean pending, final boolean pending,
@NonNull final User currentUser) { @NonNull final User currentUser) {
super(application); super(application);
@ -74,7 +74,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
contentResolver = application.getContentResolver(); contentResolver = application.getContentResolver();
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings"); recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance(); final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
threadManager = messagesManager.getThreadManager(threadId, pending, backup, currentUser, contentResolver); threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
threadManager.fetchPendingRequests(); threadManager.fetchPendingRequests();
} }
@ -278,16 +278,24 @@ public class DirectThreadViewModel extends AndroidViewModel {
return threadManager.declineRequest(); return threadManager.declineRequest();
} }
public void markAsSeen() { public LiveData<Resource<Object>> markAsSeen() {
if (currentUser == null) return; if (currentUser == null) {
return getSuccessEventResObjectLiveData();
}
final DirectThread thread = getThread().getValue(); final DirectThread thread = getThread().getValue();
if (thread == null) return; if (thread == null) {
return getSuccessEventResObjectLiveData();
}
final List<DirectItem> items = thread.getItems(); final List<DirectItem> items = thread.getItems();
if (items == null || items.isEmpty()) return; if (items == null || items.isEmpty()) {
return getSuccessEventResObjectLiveData();
}
final Optional<DirectItem> itemOptional = items.stream() final Optional<DirectItem> itemOptional = items.stream()
.filter(item -> item.getUserId() != currentUser.getPk()) .filter(item -> item.getUserId() != currentUser.getPk())
.findFirst(); .findFirst();
if (!itemOptional.isPresent()) return; if (!itemOptional.isPresent()) {
return getSuccessEventResObjectLiveData();
}
final DirectItem directItem = itemOptional.get(); final DirectItem directItem = itemOptional.get();
final Map<Long, DirectThreadLastSeenAt> lastSeenAt = thread.getLastSeenAt(); final Map<Long, DirectThreadLastSeenAt> lastSeenAt = thread.getLastSeenAt();
if (lastSeenAt != null) { if (lastSeenAt != null) {
@ -296,10 +304,29 @@ public class DirectThreadViewModel extends AndroidViewModel {
if (seenAt != null if (seenAt != null
&& (Objects.equals(seenAt.getItemId(), directItem.getItemId()) && (Objects.equals(seenAt.getItemId(), directItem.getItemId())
|| Long.parseLong(seenAt.getTimestamp()) >= directItem.getTimestamp())) { || Long.parseLong(seenAt.getTimestamp()) >= directItem.getTimestamp())) {
return; return getSuccessEventResObjectLiveData();
} }
} catch (Exception ignored) {} } catch (Exception ignored) {
return getSuccessEventResObjectLiveData();
}
} }
threadManager.markAsSeen(directItem); return threadManager.markAsSeen(directItem);
} }
@NonNull
private MutableLiveData<Resource<Object>> getSuccessEventResObjectLiveData() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.success(new Object()));
return data;
}
public void deleteThreadIfRequired() {
final DirectThread thread = getThread().getValue();
if (thread == null) return;
if (thread.isTemp() && (thread.getItems() == null || thread.getItems().isEmpty())) {
final InboxManager inboxManager = DirectMessagesManager.getInstance().getInboxManager();
inboxManager.removeThread(threadId);
}
}
} }

View File

@ -7,25 +7,21 @@ import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.viewmodels.DirectSettingsViewModel; import awais.instagrabber.viewmodels.DirectSettingsViewModel;
public class DirectSettingsViewModelFactory implements ViewModelProvider.Factory { public class DirectSettingsViewModelFactory implements ViewModelProvider.Factory {
private final Application application; private final Application application;
private final String threadId; private final String threadId;
private final DirectThread backup;
private final boolean pending; private final boolean pending;
private final User currentUser; private final User currentUser;
public DirectSettingsViewModelFactory(@NonNull final Application application, public DirectSettingsViewModelFactory(@NonNull final Application application,
@NonNull final String threadId, @NonNull final String threadId,
@NonNull final DirectThread backup,
final boolean pending, final boolean pending,
@NonNull final User currentUser) { @NonNull final User currentUser) {
this.application = application; this.application = application;
this.threadId = threadId; this.threadId = threadId;
this.backup = backup;
this.pending = pending; this.pending = pending;
this.currentUser = currentUser; this.currentUser = currentUser;
} }
@ -34,6 +30,6 @@ public class DirectSettingsViewModelFactory implements ViewModelProvider.Factory
@Override @Override
public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) { public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) {
//noinspection unchecked //noinspection unchecked
return (T) new DirectSettingsViewModel(application, threadId, backup, pending, currentUser); return (T) new DirectSettingsViewModel(application, threadId, pending, currentUser);
} }
} }

View File

@ -7,25 +7,21 @@ import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import awais.instagrabber.repositories.responses.User; import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.viewmodels.DirectThreadViewModel; import awais.instagrabber.viewmodels.DirectThreadViewModel;
public class DirectThreadViewModelFactory implements ViewModelProvider.Factory { public class DirectThreadViewModelFactory implements ViewModelProvider.Factory {
private final Application application; private final Application application;
private final String threadId; private final String threadId;
private final DirectThread backup;
private final boolean pending; private final boolean pending;
private final User currentUser; private final User currentUser;
public DirectThreadViewModelFactory(@NonNull final Application application, public DirectThreadViewModelFactory(@NonNull final Application application,
@NonNull final String threadId, @NonNull final String threadId,
final DirectThread backup,
final boolean pending, final boolean pending,
@NonNull final User currentUser) { @NonNull final User currentUser) {
this.application = application; this.application = application;
this.threadId = threadId; this.threadId = threadId;
this.backup = backup;
this.pending = pending; this.pending = pending;
this.currentUser = currentUser; this.currentUser = currentUser;
} }
@ -34,6 +30,6 @@ public class DirectThreadViewModelFactory implements ViewModelProvider.Factory {
@Override @Override
public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) { public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) {
//noinspection unchecked //noinspection unchecked
return (T) new DirectThreadViewModel(application, threadId, backup, pending, currentUser); return (T) new DirectThreadViewModel(application, threadId, pending, currentUser);
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<item android:drawable="@color/grey_900" />
<item>
<bitmap
android:gravity="center"
android:src="@drawable/barinsta_logo" />
</item>
</layer-list>

View File

@ -257,7 +257,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="250dp" android:layout_height="250dp"
android:translationY="250dp" android:translationY="250dp"
android:visibility="gone" android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@ -8,7 +8,7 @@
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/mark_as_seen" android:id="@+id/mark_as_seen"
android:icon="@drawable/ic_outline_views_24" android:icon="@drawable/ic_check_all_24"
android:title="@string/mark_as_seen" android:title="@string/mark_as_seen"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item

View File

@ -122,10 +122,6 @@
android:name="pending" android:name="pending"
android:defaultValue="false" android:defaultValue="false"
app:argType="boolean" /> app:argType="boolean" />
<argument
android:name="backup"
app:nullable="true"
app:argType="awais.instagrabber.repositories.responses.directmessages.DirectThread" />
<action <action
android:id="@+id/action_thread_to_settings" android:id="@+id/action_thread_to_settings"
app:destination="@id/directMessagesSettingsFragment" /> app:destination="@id/directMessagesSettingsFragment" />
@ -156,11 +152,6 @@
android:defaultValue="false" android:defaultValue="false"
app:argType="boolean" /> app:argType="boolean" />
<argument
android:name="backup"
app:nullable="true"
app:argType="awais.instagrabber.repositories.responses.directmessages.DirectThread" />
<action <action
android:id="@+id/action_settings_to_inbox" android:id="@+id/action_settings_to_inbox"
app:destination="@id/directMessagesInboxFragment" app:destination="@id/directMessagesInboxFragment"

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -471,4 +471,5 @@
<string name="edit_keyword_filter">Edit keyword filters</string> <string name="edit_keyword_filter">Edit keyword filters</string>
<string name="added_keywords">Added keyword: {0} to filter list</string> <string name="added_keywords">Added keyword: {0} to filter list</string>
<string name="removed_keywords">Removed keyword: {0} from filter list</string> <string name="removed_keywords">Removed keyword: {0} from filter list</string>
<string name="marked_as_seen">Marked as seen</string>
</resources> </resources>

View File

@ -140,4 +140,8 @@
<item name="dmOutgoingBgColor">@color/deep_purple_400</item> <item name="dmOutgoingBgColor">@color/deep_purple_400</item>
<item name="dmDateHeaderBgColor">@color/deep_purple_600</item> <item name="dmDateHeaderBgColor">@color/deep_purple_600</item>
</style> </style>
<style name="AppTheme.Launcher" parent="AppTheme.Dark">
<item name="android:windowBackground">@drawable/launch_screen</item>
</style>
</resources> </resources>

View File

@ -5,7 +5,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.2' classpath 'com.android.tools.build:gradle:4.1.3'
def nav_version = "2.3.4" def nav_version = "2.3.4"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
} }

6
renovate.json Normal file
View File

@ -0,0 +1,6 @@
{
"extends": [
"config:base"
],
"prConcurrentLimit": 5
}