mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 14:47:29 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
700711f5f3
@ -111,7 +111,6 @@ dependencies {
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
|
||||
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:android-gpuimage:2.1.1-beta4'
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.Light.White"
|
||||
android:theme="@style/AppTheme.Launcher"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
|
@ -72,7 +72,6 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.IntentModel;
|
||||
import awais.instagrabber.models.SuggestionModel;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.services.ActivityCheckerService;
|
||||
import awais.instagrabber.services.DMSyncAlarmReceiver;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
@ -251,7 +250,17 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
|
||||
@Override
|
||||
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();
|
||||
return;
|
||||
}
|
||||
@ -577,10 +586,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
private void showThread(@NonNull final Intent intent) {
|
||||
final String threadId = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_ID);
|
||||
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;
|
||||
currentNavControllerLiveData.observe(this, new Observer<NavController>() {
|
||||
@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
|
||||
new Handler().post(() -> {
|
||||
final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections
|
||||
.actionInboxToThread(threadId, threadTitle, backup);
|
||||
.actionInboxToThread(threadId, threadTitle);
|
||||
navController.navigate(action);
|
||||
});
|
||||
return;
|
||||
@ -607,7 +616,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
@Nullable final Bundle arguments) {
|
||||
if (destination.getId() == R.id.directMessagesInboxFragment) {
|
||||
final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections
|
||||
.actionInboxToThread(threadId, threadTitle, backup);
|
||||
.actionInboxToThread(threadId, threadTitle);
|
||||
controller.navigate(action);
|
||||
controller.removeOnDestinationChangedListener(this);
|
||||
}
|
||||
|
@ -12,4 +12,7 @@ public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback
|
||||
|
||||
@Override
|
||||
public void onPlayerPause(final int position) {}
|
||||
|
||||
@Override
|
||||
public void onPlayerRelease(final int position) {}
|
||||
}
|
||||
|
@ -148,5 +148,7 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
|
||||
void onPlayerPlay(int position);
|
||||
|
||||
void onPlayerPause(int position);
|
||||
|
||||
void onPlayerRelease(int position);
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,13 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
|
||||
sliderCallback.onPlayerPause(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease() {
|
||||
if (sliderCallback != null) {
|
||||
sliderCallback.onPlayerRelease(position);
|
||||
}
|
||||
}
|
||||
};
|
||||
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
|
||||
String videoUrl = null;
|
||||
|
@ -15,4 +15,7 @@ public class VideoPlayerCallbackAdapter implements VideoPlayerViewHelper.VideoPl
|
||||
|
||||
@Override
|
||||
public void onPause() {}
|
||||
|
||||
@Override
|
||||
public void onRelease() {}
|
||||
}
|
||||
|
@ -359,6 +359,9 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
// }
|
||||
|
||||
public void releasePlayer() {
|
||||
if (videoPlayerCallback != null) {
|
||||
videoPlayerCallback.onRelease();
|
||||
}
|
||||
if (player != null) {
|
||||
player.release();
|
||||
player = null;
|
||||
@ -453,5 +456,7 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
void onPlay();
|
||||
|
||||
void onPause();
|
||||
|
||||
void onRelease();
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,18 @@ public class EmojiCategory {
|
||||
|
||||
public EmojiCategory(final EmojiCategoryType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public EmojiCategoryType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Map<String, Emoji> getEmojis() {
|
||||
return emojis;
|
||||
}
|
||||
|
||||
public int getDrawableRes() {
|
||||
if (drawableRes == 0) {
|
||||
switch (type) {
|
||||
case SMILEYS_AND_EMOTION:
|
||||
drawableRes = R.drawable.ic_round_emoji_emotions_24;
|
||||
@ -46,16 +58,6 @@ public class EmojiCategory {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public EmojiCategoryType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Map<String, Emoji> getEmojis() {
|
||||
return emojis;
|
||||
}
|
||||
|
||||
public int getDrawableRes() {
|
||||
return drawableRes;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ import androidx.core.content.PermissionChecker;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.widget.NestedScrollView;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
@ -1062,15 +1063,28 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
||||
|
||||
@Override
|
||||
public void onPlayerPlay(final int position) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
Utils.enabledKeepScreenOn(activity);
|
||||
if (!detailsVisible || hasBeenToggled) return;
|
||||
showPlayerControls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerPause(final int position) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
Utils.disableKeepScreenOn(activity);
|
||||
if (detailsVisible || hasBeenToggled) return;
|
||||
toggleDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerRelease(final int position) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
Utils.disableKeepScreenOn(activity);
|
||||
}
|
||||
});
|
||||
binding.sliderParent.setAdapter(sliderItemsAdapter);
|
||||
if (sliderPosition >= 0 && sliderPosition < media.getCarouselMedia().size()) {
|
||||
@ -1206,7 +1220,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
||||
|
||||
@Override
|
||||
public void onPlayerViewLoaded() {
|
||||
binding.playerControls.getRoot().setVisibility(View.VISIBLE);
|
||||
// binding.playerControls.getRoot().setVisibility(View.VISIBLE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.videoPost.playerView.getLayoutParams();
|
||||
final int requiredWidth = Utils.displayMetrics.widthPixels;
|
||||
final int resultingHeight = NumberUtils
|
||||
@ -1218,10 +1232,27 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
|
||||
|
||||
@Override
|
||||
public void onPlay() {
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
Utils.enabledKeepScreenOn(activity);
|
||||
if (detailsVisible) {
|
||||
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();
|
||||
String videoUrl = null;
|
||||
|
@ -257,7 +257,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
navigating = true;
|
||||
if (isAdded()) {
|
||||
final DirectMessageInboxFragmentDirections.ActionInboxToThread directions = DirectMessageInboxFragmentDirections
|
||||
.actionInboxToThread(thread.getThreadId(), thread.getThreadTitle(), thread);
|
||||
.actionInboxToThread(thread.getThreadId(), thread.getThreadTitle());
|
||||
NavHostFragment.findNavController(this).navigate(directions);
|
||||
}
|
||||
navigating = false;
|
||||
|
@ -81,7 +81,6 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
final AppStateViewModel appStateViewModel = new ViewModelProvider(fragmentActivity).get(AppStateViewModel.class);
|
||||
viewModel = new ViewModelProvider(this, new DirectSettingsViewModelFactory(fragmentActivity.getApplication(),
|
||||
args.getThreadId(),
|
||||
args.getBackup(),
|
||||
args.getPending(),
|
||||
appStateViewModel.getCurrentUser()))
|
||||
.get(DirectSettingsViewModel.class);
|
||||
@ -348,15 +347,15 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
usersAdapter = new DirectUsersAdapter(
|
||||
inviter != null ? inviter.getPk() : -1,
|
||||
(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());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (TextUtils.isEmpty(user.getUsername())) return;
|
||||
final ProfileNavGraphDirections.ActionGlobalProfileFragment directions = ProfileNavGraphDirections
|
||||
.actionGlobalProfileFragment()
|
||||
.setUsername("@" + user.getUsername());
|
||||
NavHostFragment.findNavController(this).navigate(directions);
|
||||
}
|
||||
},
|
||||
(position, user) -> {
|
||||
final ArrayList<Option<String>> options = viewModel.createUserOptions(user);
|
||||
|
@ -100,6 +100,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DMUtils;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.PermissionUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
@ -317,6 +318,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
backStackSavedStateResultLiveData.postValue(null);
|
||||
};
|
||||
private final MutableLiveData<Integer> inputLength = new MutableLiveData<>(0);
|
||||
private MenuItem markAsSeenMenuItem;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
@ -329,7 +331,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments);
|
||||
viewModel = new ViewModelProvider(this, new DirectThreadViewModelFactory(fragmentActivity.getApplication(),
|
||||
fragmentArgs.getThreadId(),
|
||||
fragmentArgs.getBackup(),
|
||||
fragmentArgs.getPending(),
|
||||
appStateViewModel.getCurrentUser()))
|
||||
.get(DirectThreadViewModel.class);
|
||||
@ -368,9 +369,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||
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 (autoMarkAsSeen) {
|
||||
markAsSeenMenuItem.setVisible(false);
|
||||
} else {
|
||||
markAsSeenMenuItem.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,15 +384,14 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
final int itemId = item.getItemId();
|
||||
if (itemId == R.id.info) {
|
||||
final DirectMessageThreadFragmentDirections.ActionThreadToSettings directions = DirectMessageThreadFragmentDirections
|
||||
.actionThreadToSettings(viewModel.getThreadId(), null, null);
|
||||
.actionThreadToSettings(viewModel.getThreadId(), null);
|
||||
final Boolean pending = viewModel.isPending().getValue();
|
||||
directions.setPending(pending == null ? false : pending);
|
||||
NavHostFragment.findNavController(this).navigate(directions);
|
||||
return true;
|
||||
}
|
||||
if (itemId == R.id.mark_as_seen) {
|
||||
// new ThreadAction().execute("seen", lastMessage);
|
||||
item.setVisible(false);
|
||||
handleMarkAsSeen(item);
|
||||
return true;
|
||||
}
|
||||
if (itemId == R.id.refresh && viewModel != null) {
|
||||
@ -397,6 +401,40 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
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
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
@ -464,6 +502,12 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
viewModel.deleteThreadIfRequired();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeExperimentalUsageError")
|
||||
private void cleanup() {
|
||||
if (prevTitleRunnable != null) {
|
||||
@ -903,9 +947,15 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
|
||||
private void submitItemsToAdapter(final List<DirectItem> items) {
|
||||
binding.chats.post(() -> {
|
||||
if (autoMarkAsSeen) {
|
||||
binding.chats.post(() -> viewModel.markAsSeen());
|
||||
viewModel.markAsSeen();
|
||||
return;
|
||||
}
|
||||
final DirectThread thread = threadLiveData.getValue();
|
||||
if (thread == null) return;
|
||||
markAsSeenMenuItem.setEnabled(!DMUtils.isRead(thread));
|
||||
});
|
||||
if (itemsAdapter == null) return;
|
||||
itemsAdapter.submitList(items, () -> {
|
||||
itemOrHeaders = itemsAdapter.getList();
|
||||
|
@ -163,7 +163,7 @@ public class DirectPendingInboxFragment extends Fragment implements SwipeRefresh
|
||||
navigating = true;
|
||||
if (isAdded()) {
|
||||
final DirectPendingInboxFragmentDirections.ActionPendingInboxToThread directions = DirectPendingInboxFragmentDirections
|
||||
.actionPendingInboxToThread(thread.getThreadId(), thread.getThreadTitle(), thread);
|
||||
.actionPendingInboxToThread(thread.getThreadId(), thread.getThreadTitle());
|
||||
directions.setPending(true);
|
||||
NavHostFragment.findNavController(this).navigate(directions);
|
||||
}
|
||||
|
@ -74,6 +74,8 @@ import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||
import awais.instagrabber.dialogs.ProfilePicDialogFragment;
|
||||
import awais.instagrabber.fragments.PostViewV2Fragment;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.managers.DirectMessagesManager;
|
||||
import awais.instagrabber.managers.InboxManager;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
@ -590,8 +592,11 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
|
||||
private void fetchProfileDetails() {
|
||||
accountIsUpdated = false;
|
||||
new ProfileFetcher(TextUtils.isEmpty(username) ? null : username.trim().substring(1),
|
||||
myId, isLoggedIn, new FetchListener<User>() {
|
||||
String usernameTemp = username.trim();
|
||||
if (usernameTemp.startsWith("@")) {
|
||||
usernameTemp = usernameTemp.substring(1);
|
||||
}
|
||||
new ProfileFetcher(TextUtils.isEmpty(username) ? null : usernameTemp, myId, isLoggedIn, new FetchListener<User>() {
|
||||
@Override
|
||||
public void onResult(final User user) {
|
||||
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,
|
||||
Toast.LENGTH_LONG).show();
|
||||
else Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
} catch (final Throwable e) {}
|
||||
} catch (final Throwable ignored) {}
|
||||
}
|
||||
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
@ -1073,7 +1078,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
profileDetailsBinding.btnDM.setEnabled(true);
|
||||
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);
|
||||
}).execute();
|
||||
});
|
||||
|
@ -74,9 +74,8 @@ public final class DirectMessagesManager {
|
||||
|
||||
public ThreadManager getThreadManager(@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
final DirectThread backup,
|
||||
@NonNull final User currentUser,
|
||||
@NonNull final ContentResolver contentResolver) {
|
||||
return ThreadManager.getInstance(threadId, pending, backup, currentUser, contentResolver);
|
||||
return ThreadManager.getInstance(threadId, pending, currentUser, contentResolver);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -357,4 +358,15 @@ public final class InboxManager {
|
||||
public void setPendingRequestsTotal(final int 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,6 @@ public final class ThreadManager {
|
||||
|
||||
public static ThreadManager getInstance(@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
final DirectThread backup,
|
||||
@NonNull final User currentUser,
|
||||
@NonNull final ContentResolver contentResolver) {
|
||||
ThreadManager instance = INSTANCE_MAP.get(threadId);
|
||||
@ -131,7 +130,7 @@ public final class ThreadManager {
|
||||
synchronized (LOCK) {
|
||||
instance = INSTANCE_MAP.get(threadId);
|
||||
if (instance == null) {
|
||||
instance = new ThreadManager(threadId, pending, backup, currentUser, contentResolver);
|
||||
instance = new ThreadManager(threadId, pending, currentUser, contentResolver);
|
||||
INSTANCE_MAP.put(threadId, instance);
|
||||
}
|
||||
}
|
||||
@ -145,7 +144,6 @@ public final class ThreadManager {
|
||||
|
||||
private ThreadManager(@NonNull final String threadId,
|
||||
final boolean pending,
|
||||
final DirectThread backup,
|
||||
@NonNull final User currentUser,
|
||||
@NonNull final ContentResolver contentResolver) {
|
||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
||||
@ -164,17 +162,17 @@ public final class ThreadManager {
|
||||
service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
|
||||
mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId);
|
||||
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, viewerId);
|
||||
setupTransformations(backup);
|
||||
setupTransformations();
|
||||
// fetchChats();
|
||||
}
|
||||
|
||||
public void moveFromPending() {
|
||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
||||
this.inboxManager = messagesManager.getInboxManager();
|
||||
setupTransformations(null);
|
||||
setupTransformations();
|
||||
}
|
||||
|
||||
private void setupTransformations(final DirectThread backup) {
|
||||
private void setupTransformations() {
|
||||
// Transformations
|
||||
thread = distinctUntilChanged(map(inboxManager.getInbox(), inboxResource -> {
|
||||
if (inboxResource == null) {
|
||||
@ -188,7 +186,7 @@ public final class ThreadManager {
|
||||
final DirectThread thread = threads.stream()
|
||||
.filter(t -> t.getThreadId().equals(threadId))
|
||||
.findFirst()
|
||||
.orElse(backup);
|
||||
.orElse(null);
|
||||
if (thread != null) {
|
||||
cursor = thread.getOldestCursor();
|
||||
hasOlder = thread.hasOlder();
|
||||
@ -1799,18 +1797,23 @@ public final class ThreadManager {
|
||||
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);
|
||||
request.enqueue(new Callback<DirectItemSeenResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectItemSeenResponse> call,
|
||||
@NonNull final Response<DirectItemSeenResponse> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
handleErrorBody(call, response, null);
|
||||
handleErrorBody(call, response, data);
|
||||
return;
|
||||
}
|
||||
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();
|
||||
final DirectItemSeenResponsePayload payload = seenResponse.getPayload();
|
||||
if (payload == null) return;
|
||||
@ -1822,14 +1825,17 @@ public final class ThreadManager {
|
||||
lastSeenAt.put(currentUser.getPk(), new DirectThreadLastSeenAt(timestamp, directItem.getItemId()));
|
||||
thread.setLastSeenAt(lastSeenAt);
|
||||
setThread(thread, true);
|
||||
data.postValue(Resource.success(new Object()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectItemSeenResponse> call,
|
||||
@NonNull final Throwable t) {
|
||||
Log.e(TAG, "onFailure: ", t);
|
||||
data.postValue(Resource.error(t.getMessage(), null));
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
private interface OnSuccessAction {
|
||||
|
@ -45,6 +45,7 @@ public class DirectThread implements Serializable, Cloneable {
|
||||
private boolean approvalRequiredForNewMembers;
|
||||
private int inputMode;
|
||||
private final List<ThreadContext> threadContextItems;
|
||||
private boolean isTemp;
|
||||
|
||||
public DirectThread(final String threadId,
|
||||
final String threadV2Id,
|
||||
@ -292,6 +293,14 @@ public class DirectThread implements Serializable, Cloneable {
|
||||
return threadContextItems;
|
||||
}
|
||||
|
||||
public boolean isTemp() {
|
||||
return isTemp;
|
||||
}
|
||||
|
||||
public void setTemp(final boolean isTemp) {
|
||||
this.isTemp = isTemp;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DirectItem getFirstDirectItem() {
|
||||
DirectItem firstItem = null;
|
||||
|
@ -359,4 +359,16 @@ public final class Utils {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -2,27 +2,25 @@ package awais.instagrabber.utils.emoji;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.ibm.icu.impl.Utility;
|
||||
import com.ibm.icu.lang.CharSequences;
|
||||
import com.ibm.icu.text.UnicodeSet;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
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.EmojiCategory;
|
||||
import awais.instagrabber.customviews.emoji.EmojiCategoryType;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
|
||||
public final class EmojiParser {
|
||||
private static final String TAG = EmojiParser.class.getSimpleName();
|
||||
@ -30,51 +28,8 @@ public final class EmojiParser {
|
||||
|
||||
private static EmojiParser instance;
|
||||
|
||||
// private static final String COMBINING_ENCLOSING_KEYCAP = "\u20E3";
|
||||
// private static final String ZWJ = "\u200D";
|
||||
// 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 Map<String, Emoji> allEmojis = Collections.emptyMap();
|
||||
private Map<EmojiCategoryType, EmojiCategory> categoryMap = Collections.emptyMap();
|
||||
private ImmutableList<EmojiCategory> categories;
|
||||
|
||||
public static EmojiParser getInstance() {
|
||||
@ -89,267 +44,56 @@ public final class EmojiParser {
|
||||
}
|
||||
|
||||
private EmojiParser() {
|
||||
// Log.d(TAG, "Emoji: " + new Date());
|
||||
// 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 String file = "res/raw/emojis.json";
|
||||
final ClassLoader classLoader = getClass().getClassLoader();
|
||||
if (classLoader == null) {
|
||||
Log.e(TAG, "Emoji: classLoader is null");
|
||||
return;
|
||||
}
|
||||
try (final InputStream in = classLoader.getResourceAsStream(file);
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
|
||||
String line;
|
||||
EmojiCategoryType categoryType = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("#")) {
|
||||
line = line.substring(1).trim();
|
||||
if (line.startsWith("group:")) {
|
||||
majorCategory = line.substring("group:".length()).trim();
|
||||
if (!majorCategory.equals("Component")) { // Skip Component
|
||||
if (majorCategory.equals("Smileys & Emotion") || majorCategory.equals("People & Body")) {
|
||||
// Put 'People & Body' in 'Smileys & Emotion' category
|
||||
categoryType = EmojiCategoryType.SMILEYS_AND_EMOTION;
|
||||
} else {
|
||||
categoryType = EmojiCategoryType.valueOfName(majorCategory);
|
||||
}
|
||||
final boolean contains = CATEGORY_MAP.containsKey(categoryType);
|
||||
if (!contains) {
|
||||
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());
|
||||
// }
|
||||
try (final InputStream in = classLoader.getResourceAsStream(file)) {
|
||||
final String json = NetworkUtils.readFromInputStream(in);
|
||||
final Gson gson = new Gson();
|
||||
final Type type = new TypeToken<Map<EmojiCategoryType, EmojiCategory>>() {}.getType();
|
||||
categoryMap = gson.fromJson(json, type);
|
||||
// Log.d(TAG, "EmojiParser: " + categoryMap);
|
||||
allEmojis = categoryMap.values()
|
||||
.stream()
|
||||
.flatMap((Function<EmojiCategory, Stream<Emoji>>) emojiCategory -> {
|
||||
final Map<String, Emoji> emojis = emojiCategory.getEmojis();
|
||||
return emojis.values().stream();
|
||||
})
|
||||
.flatMap(emoji -> ImmutableList.<Emoji>builder()
|
||||
.add(emoji)
|
||||
.addAll(emoji.getVariants())
|
||||
.build()
|
||||
.stream())
|
||||
.collect(Collectors.toMap(Emoji::getUnicode, Function.identity()));
|
||||
} 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() {
|
||||
return CATEGORY_MAP;
|
||||
return categoryMap;
|
||||
}
|
||||
|
||||
public List<EmojiCategory> getEmojiCategories() {
|
||||
if (categories == null) {
|
||||
final Collection<EmojiCategory> categoryCollection = CATEGORY_MAP.values();
|
||||
final Collection<EmojiCategory> categoryCollection = categoryMap.values();
|
||||
categories = ImmutableList.copyOf(categoryCollection);
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
public Map<String, Emoji> getAllEmojis() {
|
||||
return ALL_EMOJIS;
|
||||
return allEmojis;
|
||||
}
|
||||
|
||||
public Emoji getEmoji(final String emoji) {
|
||||
if (emoji == 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();
|
||||
// }
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -45,7 +45,6 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
|
||||
public DirectSettingsViewModel(final Application application,
|
||||
@NonNull final String threadId,
|
||||
final DirectThread backup,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
super(application);
|
||||
@ -59,7 +58,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
|
||||
final ContentResolver contentResolver = application.getContentResolver();
|
||||
resources = getApplication().getResources();
|
||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
||||
threadManager = messagesManager.getThreadManager(threadId, pending, backup, currentUser, contentResolver);
|
||||
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -23,6 +23,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.customviews.emoji.Emoji;
|
||||
import awais.instagrabber.managers.DirectMessagesManager;
|
||||
import awais.instagrabber.managers.InboxManager;
|
||||
import awais.instagrabber.managers.ThreadManager;
|
||||
import awais.instagrabber.models.Resource;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
@ -57,7 +58,6 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
||||
|
||||
public DirectThreadViewModel(@NonNull final Application application,
|
||||
@NonNull final String threadId,
|
||||
final DirectThread backup,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
super(application);
|
||||
@ -74,7 +74,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
||||
contentResolver = application.getContentResolver();
|
||||
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
|
||||
final DirectMessagesManager messagesManager = DirectMessagesManager.getInstance();
|
||||
threadManager = messagesManager.getThreadManager(threadId, pending, backup, currentUser, contentResolver);
|
||||
threadManager = messagesManager.getThreadManager(threadId, pending, currentUser, contentResolver);
|
||||
threadManager.fetchPendingRequests();
|
||||
}
|
||||
|
||||
@ -278,16 +278,24 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
||||
return threadManager.declineRequest();
|
||||
}
|
||||
|
||||
public void markAsSeen() {
|
||||
if (currentUser == null) return;
|
||||
public LiveData<Resource<Object>> markAsSeen() {
|
||||
if (currentUser == null) {
|
||||
return getSuccessEventResObjectLiveData();
|
||||
}
|
||||
final DirectThread thread = getThread().getValue();
|
||||
if (thread == null) return;
|
||||
if (thread == null) {
|
||||
return getSuccessEventResObjectLiveData();
|
||||
}
|
||||
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()
|
||||
.filter(item -> item.getUserId() != currentUser.getPk())
|
||||
.findFirst();
|
||||
if (!itemOptional.isPresent()) return;
|
||||
if (!itemOptional.isPresent()) {
|
||||
return getSuccessEventResObjectLiveData();
|
||||
}
|
||||
final DirectItem directItem = itemOptional.get();
|
||||
final Map<Long, DirectThreadLastSeenAt> lastSeenAt = thread.getLastSeenAt();
|
||||
if (lastSeenAt != null) {
|
||||
@ -296,10 +304,29 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
||||
if (seenAt != null
|
||||
&& (Objects.equals(seenAt.getItemId(), directItem.getItemId())
|
||||
|| 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,25 +7,21 @@ import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.viewmodels.DirectSettingsViewModel;
|
||||
|
||||
public class DirectSettingsViewModelFactory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Application application;
|
||||
private final String threadId;
|
||||
private final DirectThread backup;
|
||||
private final boolean pending;
|
||||
private final User currentUser;
|
||||
|
||||
public DirectSettingsViewModelFactory(@NonNull final Application application,
|
||||
@NonNull final String threadId,
|
||||
@NonNull final DirectThread backup,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
this.application = application;
|
||||
this.threadId = threadId;
|
||||
this.backup = backup;
|
||||
this.pending = pending;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
@ -34,6 +30,6 @@ public class DirectSettingsViewModelFactory implements ViewModelProvider.Factory
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) {
|
||||
//noinspection unchecked
|
||||
return (T) new DirectSettingsViewModel(application, threadId, backup, pending, currentUser);
|
||||
return (T) new DirectSettingsViewModel(application, threadId, pending, currentUser);
|
||||
}
|
||||
}
|
||||
|
@ -7,25 +7,21 @@ import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.viewmodels.DirectThreadViewModel;
|
||||
|
||||
public class DirectThreadViewModelFactory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Application application;
|
||||
private final String threadId;
|
||||
private final DirectThread backup;
|
||||
private final boolean pending;
|
||||
private final User currentUser;
|
||||
|
||||
public DirectThreadViewModelFactory(@NonNull final Application application,
|
||||
@NonNull final String threadId,
|
||||
final DirectThread backup,
|
||||
final boolean pending,
|
||||
@NonNull final User currentUser) {
|
||||
this.application = application;
|
||||
this.threadId = threadId;
|
||||
this.backup = backup;
|
||||
this.pending = pending;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
@ -34,6 +30,6 @@ public class DirectThreadViewModelFactory implements ViewModelProvider.Factory {
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull final Class<T> modelClass) {
|
||||
//noinspection unchecked
|
||||
return (T) new DirectThreadViewModel(application, threadId, backup, pending, currentUser);
|
||||
return (T) new DirectThreadViewModel(application, threadId, pending, currentUser);
|
||||
}
|
||||
}
|
||||
|
BIN
app/src/main/res/drawable/barinsta_logo.png
Normal file
BIN
app/src/main/res/drawable/barinsta_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
10
app/src/main/res/drawable/launch_screen.xml
Normal file
10
app/src/main/res/drawable/launch_screen.xml
Normal 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>
|
@ -257,7 +257,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="250dp"
|
||||
android:translationY="250dp"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -8,7 +8,7 @@
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
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"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
|
@ -122,10 +122,6 @@
|
||||
android:name="pending"
|
||||
android:defaultValue="false"
|
||||
app:argType="boolean" />
|
||||
<argument
|
||||
android:name="backup"
|
||||
app:nullable="true"
|
||||
app:argType="awais.instagrabber.repositories.responses.directmessages.DirectThread" />
|
||||
<action
|
||||
android:id="@+id/action_thread_to_settings"
|
||||
app:destination="@id/directMessagesSettingsFragment" />
|
||||
@ -156,11 +152,6 @@
|
||||
android:defaultValue="false"
|
||||
app:argType="boolean" />
|
||||
|
||||
<argument
|
||||
android:name="backup"
|
||||
app:nullable="true"
|
||||
app:argType="awais.instagrabber.repositories.responses.directmessages.DirectThread" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_settings_to_inbox"
|
||||
app:destination="@id/directMessagesInboxFragment"
|
||||
|
File diff suppressed because it is too large
Load Diff
1
app/src/main/res/raw/emojis.json
Normal file
1
app/src/main/res/raw/emojis.json
Normal file
File diff suppressed because one or more lines are too long
@ -471,4 +471,5 @@
|
||||
<string name="edit_keyword_filter">Edit keyword filters</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="marked_as_seen">Marked as seen</string>
|
||||
</resources>
|
||||
|
@ -140,4 +140,8 @@
|
||||
<item name="dmOutgoingBgColor">@color/deep_purple_400</item>
|
||||
<item name="dmDateHeaderBgColor">@color/deep_purple_600</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Launcher" parent="AppTheme.Dark">
|
||||
<item name="android:windowBackground">@drawable/launch_screen</item>
|
||||
</style>
|
||||
</resources>
|
@ -5,7 +5,7 @@ buildscript {
|
||||
}
|
||||
|
||||
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"
|
||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
|
||||
}
|
||||
|
6
renovate.json
Normal file
6
renovate.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"prConcurrentLimit": 5
|
||||
}
|
Loading…
Reference in New Issue
Block a user