Browse Source
Merge branch 'master' into stamatiap/development
renovate/org.robolectric-robolectric-4.x
Merge branch 'master' into stamatiap/development
renovate/org.robolectric-robolectric-4.x
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 2980 additions and 2410 deletions
-
10.github/workflows/github_nightly_release.yml
-
10.github/workflows/github_pre_release.yml
-
2.idea/compiler.xml
-
1.idea/gradle.xml
-
2.idea/misc.xml
-
1.idea/runConfigurations.xml
-
52app/build.gradle
-
31app/src/main/java/awais/instagrabber/activities/MainActivity.java
-
2app/src/main/java/awais/instagrabber/adapters/DirectItemsAdapter.java
-
16app/src/main/java/awais/instagrabber/adapters/SliderCallbackAdapter.java
-
22app/src/main/java/awais/instagrabber/adapters/SliderItemsAdapter.java
-
77app/src/main/java/awais/instagrabber/adapters/viewholder/SliderPhotoViewHolder.java
-
117app/src/main/java/awais/instagrabber/adapters/viewholder/SliderVideoViewHolder.java
-
8app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemAnimatedMediaViewHolder.java
-
8app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaShareViewHolder.java
-
9app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemMediaViewHolder.java
-
8app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemRavenMediaViewHolder.java
-
9app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemStoryShareViewHolder.java
-
4app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemViewHolder.java
-
8app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemXmaViewHolder.java
-
4app/src/main/java/awais/instagrabber/adapters/viewholder/feed/FeedSliderViewHolder.java
-
17app/src/main/java/awais/instagrabber/customviews/ChatMessageLayout.java
-
165app/src/main/java/awais/instagrabber/customviews/FormattedNumberTextView.java
-
75app/src/main/java/awais/instagrabber/customviews/FragmentNavigatorWithDefaultAnimations.java
-
60app/src/main/java/awais/instagrabber/customviews/NavHostFragmentWithDefaultAnimations.java
-
23app/src/main/java/awais/instagrabber/customviews/PostsRecyclerView.java
-
7app/src/main/java/awais/instagrabber/customviews/Tooltip.java
-
10app/src/main/java/awais/instagrabber/customviews/VideoPlayerCallbackAdapter.java
-
411app/src/main/java/awais/instagrabber/customviews/VideoPlayerViewHelper.java
-
2app/src/main/java/awais/instagrabber/customviews/drawee/ZoomableDraweeView.java
-
100app/src/main/java/awais/instagrabber/customviews/emoji/EmojiBottomSheetDialog.java
-
13app/src/main/java/awais/instagrabber/customviews/emoji/EmojiGridAdapter.java
-
163app/src/main/java/awais/instagrabber/customviews/emoji/EmojiPopupWindow.java
-
1app/src/main/java/awais/instagrabber/customviews/emoji/GoogleCompatEmojiDrawable.java
-
320app/src/main/java/awais/instagrabber/customviews/helpers/ChangeText.java
-
17app/src/main/java/awais/instagrabber/customviews/helpers/CustomHideBottomViewOnScrollBehavior.java
-
19app/src/main/java/awais/instagrabber/customviews/helpers/GridSpacingItemDecoration.java
-
9app/src/main/java/awais/instagrabber/dialogs/ProfilePicDialogFragment.java
-
54app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java
-
70app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java
-
54app/src/main/java/awais/instagrabber/fragments/LocationFragment.java
-
14app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java
-
1123app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java
-
19app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java
-
32app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java
-
21app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java
-
6app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageInboxFragment.java
-
67app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
-
50app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java
-
58app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java
-
1app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java
-
4app/src/main/java/awais/instagrabber/managers/ThreadManager.java
-
3app/src/main/java/awais/instagrabber/repositories/responses/User.java
-
10app/src/main/java/awais/instagrabber/repositories/responses/directmessages/DirectItemEmojiReaction.java
-
8app/src/main/java/awais/instagrabber/repositories/responses/directmessages/DirectItemReactions.java
-
15app/src/main/java/awais/instagrabber/utils/CombinedDrawable.java
-
32app/src/main/java/awais/instagrabber/utils/DMUtils.java
-
3app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java
-
91app/src/main/java/awais/instagrabber/utils/NullSafePair.java
-
75app/src/main/java/awais/instagrabber/utils/NumberUtils.java
-
3app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
-
51app/src/main/java/awais/instagrabber/utils/Utils.java
-
8app/src/main/java/awais/instagrabber/utils/emoji/EmojiParser.java
-
1app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
-
11app/src/main/res/anim/slide_in_right.xml
-
9app/src/main/res/anim/slide_left.xml
-
11app/src/main/res/anim/slide_out_left.xml
-
9app/src/main/res/anim/slide_right.xml
-
6app/src/main/res/drawable/ic_bookmark.xml
-
10app/src/main/res/drawable/ic_round_bookmark_border_24.xml
-
10app/src/main/res/drawable/ic_round_edit_24.xml
-
2app/src/main/res/drawable/shape_oval_light.xml
-
391app/src/main/res/layout/dialog_post_view.xml
-
2app/src/main/res/layout/fragment_collection_posts.xml
-
3app/src/main/res/layout/fragment_discover.xml
-
45app/src/main/res/layout/fragment_feed.xml
-
23app/src/main/res/layout/fragment_hashtag.xml
-
23app/src/main/res/layout/fragment_location.xml
-
38app/src/main/res/layout/fragment_profile.xml
-
2app/src/main/res/layout/fragment_topic_posts.xml
-
1app/src/main/res/layout/item_highlight.xml
-
15app/src/main/res/layout/layout_dm_base.xml
-
2app/src/main/res/layout/layout_dm_text.xml
-
158app/src/main/res/layout/layout_exo_custom_controls.xml
-
3app/src/main/res/layout/layout_hashtag_details.xml
-
35app/src/main/res/layout/layout_location_details.xml
-
208app/src/main/res/layout/layout_post_view_bottom.xml
-
7app/src/main/res/layout/layout_profile_details.xml
-
24app/src/main/res/layout/layout_video_player_with_thumbnail.xml
-
8app/src/main/res/menu/collection_posts_menu.xml
-
18app/src/main/res/navigation/direct_messages_nav_graph.xml
-
17app/src/main/res/navigation/discover_nav_graph.xml
-
17app/src/main/res/navigation/feed_nav_graph.xml
-
17app/src/main/res/navigation/hashtag_nav_graph.xml
-
17app/src/main/res/navigation/location_nav_graph.xml
-
17app/src/main/res/navigation/notification_viewer_nav_graph.xml
-
21app/src/main/res/navigation/profile_nav_graph.xml
-
23app/src/main/res/navigation/saved_nav_graph.xml
-
5app/src/main/res/values/drawables.xml
-
2app/src/main/res/values/strings.xml
@ -1,6 +1,6 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
<project version="4"> |
||||
<component name="CompilerConfiguration"> |
<component name="CompilerConfiguration"> |
||||
<bytecodeTargetLevel target="1.8" /> |
<bytecodeTargetLevel target="11" /> |
||||
</component> |
</component> |
||||
</project> |
</project> |
@ -0,0 +1,165 @@ |
|||||
|
package awais.instagrabber.customviews; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.util.AttributeSet; |
||||
|
import android.util.Log; |
||||
|
import android.view.ViewGroup; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.appcompat.widget.AppCompatTextView; |
||||
|
import androidx.transition.ChangeBounds; |
||||
|
import androidx.transition.Transition; |
||||
|
import androidx.transition.TransitionManager; |
||||
|
import androidx.transition.TransitionSet; |
||||
|
|
||||
|
import java.time.Duration; |
||||
|
|
||||
|
import awais.instagrabber.customviews.helpers.ChangeText; |
||||
|
import awais.instagrabber.utils.NumberUtils; |
||||
|
|
||||
|
public class FormattedNumberTextView extends AppCompatTextView { |
||||
|
private static final String TAG = FormattedNumberTextView.class.getSimpleName(); |
||||
|
private static final Transition TRANSITION; |
||||
|
|
||||
|
private long number = Long.MIN_VALUE; |
||||
|
private boolean showAbbreviation = true; |
||||
|
private boolean animateChanges = false; |
||||
|
private boolean toggleOnClick = true; |
||||
|
private boolean autoToggleToAbbreviation = true; |
||||
|
private long autoToggleTimeoutMs = Duration.ofSeconds(2).toMillis(); |
||||
|
private boolean initDone = false; |
||||
|
|
||||
|
static { |
||||
|
final TransitionSet transitionSet = new TransitionSet(); |
||||
|
final ChangeText changeText = new ChangeText().setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN); |
||||
|
transitionSet.addTransition(changeText).addTransition(new ChangeBounds()); |
||||
|
TRANSITION = transitionSet; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public FormattedNumberTextView(@NonNull final Context context) { |
||||
|
super(context); |
||||
|
init(); |
||||
|
} |
||||
|
|
||||
|
public FormattedNumberTextView(@NonNull final Context context, @Nullable final AttributeSet attrs) { |
||||
|
super(context, attrs); |
||||
|
init(); |
||||
|
} |
||||
|
|
||||
|
public FormattedNumberTextView(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyleAttr) { |
||||
|
super(context, attrs, defStyleAttr); |
||||
|
init(); |
||||
|
} |
||||
|
|
||||
|
private void init() { |
||||
|
if (initDone) return; |
||||
|
setupClickToggle(); |
||||
|
initDone = true; |
||||
|
} |
||||
|
|
||||
|
private void setupClickToggle() { |
||||
|
setOnClickListener(null); |
||||
|
} |
||||
|
|
||||
|
private OnClickListener getWrappedClickListener(@Nullable final OnClickListener l) { |
||||
|
if (!toggleOnClick) { |
||||
|
return l; |
||||
|
} |
||||
|
return v -> { |
||||
|
toggleAbbreviation(); |
||||
|
if (l != null) { |
||||
|
l.onClick(this); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public void setNumber(final long number) { |
||||
|
if (this.number == number) return; |
||||
|
this.number = number; |
||||
|
format(); |
||||
|
} |
||||
|
|
||||
|
public void clearNumber() { |
||||
|
if (number == Long.MIN_VALUE) return; |
||||
|
number = Long.MIN_VALUE; |
||||
|
format(); |
||||
|
} |
||||
|
|
||||
|
public void setShowAbbreviation(final boolean showAbbreviation) { |
||||
|
if (this.showAbbreviation && showAbbreviation) return; |
||||
|
this.showAbbreviation = showAbbreviation; |
||||
|
format(); |
||||
|
} |
||||
|
|
||||
|
public boolean isShowAbbreviation() { |
||||
|
return showAbbreviation; |
||||
|
} |
||||
|
|
||||
|
private void toggleAbbreviation() { |
||||
|
if (number == Long.MIN_VALUE) return; |
||||
|
setShowAbbreviation(!showAbbreviation); |
||||
|
} |
||||
|
|
||||
|
public void setToggleOnClick(final boolean toggleOnClick) { |
||||
|
this.toggleOnClick = toggleOnClick; |
||||
|
} |
||||
|
|
||||
|
public boolean isToggleOnClick() { |
||||
|
return toggleOnClick; |
||||
|
} |
||||
|
|
||||
|
public void setAutoToggleToAbbreviation(final boolean autoToggleToAbbreviation) { |
||||
|
this.autoToggleToAbbreviation = autoToggleToAbbreviation; |
||||
|
} |
||||
|
|
||||
|
public boolean isAutoToggleToAbbreviation() { |
||||
|
return autoToggleToAbbreviation; |
||||
|
} |
||||
|
|
||||
|
public void setAutoToggleTimeoutMs(final long autoToggleTimeoutMs) { |
||||
|
this.autoToggleTimeoutMs = autoToggleTimeoutMs; |
||||
|
} |
||||
|
|
||||
|
public long getAutoToggleTimeoutMs() { |
||||
|
return autoToggleTimeoutMs; |
||||
|
} |
||||
|
|
||||
|
public void setAnimateChanges(final boolean animateChanges) { |
||||
|
this.animateChanges = animateChanges; |
||||
|
} |
||||
|
|
||||
|
public boolean isAnimateChanges() { |
||||
|
return animateChanges; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setOnClickListener(@Nullable final OnClickListener l) { |
||||
|
super.setOnClickListener(getWrappedClickListener(l)); |
||||
|
} |
||||
|
|
||||
|
private void format() { |
||||
|
post(() -> { |
||||
|
if (animateChanges) { |
||||
|
try { |
||||
|
TransitionManager.beginDelayedTransition((ViewGroup) getParent(), TRANSITION); |
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "format: ", e); |
||||
|
} |
||||
|
} |
||||
|
if (number == Long.MIN_VALUE) { |
||||
|
setText(null); |
||||
|
return; |
||||
|
} |
||||
|
if (showAbbreviation) { |
||||
|
setText(NumberUtils.abbreviate(number)); |
||||
|
return; |
||||
|
} |
||||
|
setText(String.valueOf(number)); |
||||
|
if (autoToggleToAbbreviation) { |
||||
|
getHandler().postDelayed(() -> setShowAbbreviation(true), autoToggleTimeoutMs); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,75 @@ |
|||||
|
package awais.instagrabber.customviews; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.os.Bundle; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.fragment.app.FragmentManager; |
||||
|
import androidx.navigation.NavDestination; |
||||
|
import androidx.navigation.NavOptions; |
||||
|
import androidx.navigation.Navigator; |
||||
|
import androidx.navigation.fragment.FragmentNavigator; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
|
||||
|
@Navigator.Name("fragment") |
||||
|
public class FragmentNavigatorWithDefaultAnimations extends FragmentNavigator { |
||||
|
|
||||
|
private final NavOptions emptyNavOptions = new NavOptions.Builder().build(); |
||||
|
// private final NavOptions defaultNavOptions = new NavOptions.Builder() |
||||
|
// .setEnterAnim(R.animator.nav_default_enter_anim) |
||||
|
// .setExitAnim(R.animator.nav_default_exit_anim) |
||||
|
// .setPopEnterAnim(R.animator.nav_default_pop_enter_anim) |
||||
|
// .setPopExitAnim(R.animator.nav_default_pop_exit_anim) |
||||
|
// .build(); |
||||
|
|
||||
|
private final NavOptions defaultNavOptions = new NavOptions.Builder() |
||||
|
.setEnterAnim(R.anim.slide_in_right) |
||||
|
.setExitAnim(R.anim.slide_out_left) |
||||
|
.setPopEnterAnim(android.R.anim.slide_in_left) |
||||
|
.setPopExitAnim(android.R.anim.slide_out_right) |
||||
|
.build(); |
||||
|
|
||||
|
public FragmentNavigatorWithDefaultAnimations(@NonNull final Context context, |
||||
|
@NonNull final FragmentManager manager, |
||||
|
final int containerId) { |
||||
|
super(context, manager, containerId); |
||||
|
} |
||||
|
|
||||
|
@Nullable |
||||
|
@Override |
||||
|
public NavDestination navigate(@NonNull final Destination destination, |
||||
|
@Nullable final Bundle args, |
||||
|
@Nullable final NavOptions navOptions, |
||||
|
@Nullable final Navigator.Extras navigatorExtras) { |
||||
|
// this will try to fill in empty animations with defaults when no shared element transitions are set |
||||
|
// https://developer.android.com/guide/navigation/navigation-animate-transitions#shared-element |
||||
|
final boolean shouldUseTransitionsInstead = navigatorExtras != null; |
||||
|
final NavOptions navOptions1 = shouldUseTransitionsInstead ? navOptions : fillEmptyAnimationsWithDefaults(navOptions); |
||||
|
return super.navigate(destination, args, navOptions1, navigatorExtras); |
||||
|
} |
||||
|
|
||||
|
private NavOptions fillEmptyAnimationsWithDefaults(@Nullable final NavOptions navOptions) { |
||||
|
if (navOptions == null) { |
||||
|
return defaultNavOptions; |
||||
|
} |
||||
|
return copyNavOptionsWithDefaultAnimations(navOptions); |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
private NavOptions copyNavOptionsWithDefaultAnimations(@NonNull final NavOptions navOptions) { |
||||
|
return new NavOptions.Builder() |
||||
|
.setLaunchSingleTop(navOptions.shouldLaunchSingleTop()) |
||||
|
.setPopUpTo(navOptions.getPopUpTo(), navOptions.isPopUpToInclusive()) |
||||
|
.setEnterAnim(navOptions.getEnterAnim() == emptyNavOptions.getEnterAnim() |
||||
|
? defaultNavOptions.getEnterAnim() : navOptions.getEnterAnim()) |
||||
|
.setExitAnim(navOptions.getExitAnim() == emptyNavOptions.getExitAnim() |
||||
|
? defaultNavOptions.getExitAnim() : navOptions.getExitAnim()) |
||||
|
.setPopEnterAnim(navOptions.getPopEnterAnim() == emptyNavOptions.getPopEnterAnim() |
||||
|
? defaultNavOptions.getPopEnterAnim() : navOptions.getPopEnterAnim()) |
||||
|
.setPopExitAnim(navOptions.getPopExitAnim() == emptyNavOptions.getPopExitAnim() |
||||
|
? defaultNavOptions.getPopExitAnim() : navOptions.getPopExitAnim()) |
||||
|
.build(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,60 @@ |
|||||
|
package awais.instagrabber.customviews; |
||||
|
|
||||
|
import android.os.Bundle; |
||||
|
|
||||
|
import androidx.annotation.NavigationRes; |
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.navigation.NavController; |
||||
|
import androidx.navigation.Navigator; |
||||
|
import androidx.navigation.fragment.FragmentNavigator; |
||||
|
import androidx.navigation.fragment.NavHostFragment; |
||||
|
|
||||
|
public class NavHostFragmentWithDefaultAnimations extends NavHostFragment { |
||||
|
private static final String KEY_GRAPH_ID = "android-support-nav:fragment:graphId"; |
||||
|
private static final String KEY_START_DESTINATION_ARGS = |
||||
|
"android-support-nav:fragment:startDestinationArgs"; |
||||
|
private static final String KEY_NAV_CONTROLLER_STATE = |
||||
|
"android-support-nav:fragment:navControllerState"; |
||||
|
private static final String KEY_DEFAULT_NAV_HOST = "android-support-nav:fragment:defaultHost"; |
||||
|
|
||||
|
@NonNull |
||||
|
public static NavHostFragment create(@NavigationRes int graphResId) { |
||||
|
return create(graphResId, null); |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
public static NavHostFragment create(@NavigationRes int graphResId, |
||||
|
@Nullable Bundle startDestinationArgs) { |
||||
|
Bundle b = null; |
||||
|
if (graphResId != 0) { |
||||
|
b = new Bundle(); |
||||
|
b.putInt(KEY_GRAPH_ID, graphResId); |
||||
|
} |
||||
|
if (startDestinationArgs != null) { |
||||
|
if (b == null) { |
||||
|
b = new Bundle(); |
||||
|
} |
||||
|
b.putBundle(KEY_START_DESTINATION_ARGS, startDestinationArgs); |
||||
|
} |
||||
|
|
||||
|
final NavHostFragmentWithDefaultAnimations result = new NavHostFragmentWithDefaultAnimations(); |
||||
|
if (b != null) { |
||||
|
result.setArguments(b); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
protected Navigator<? extends FragmentNavigator.Destination> createFragmentNavigator() { |
||||
|
return new FragmentNavigatorWithDefaultAnimations(requireContext(), getChildFragmentManager(), getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreateNavController(@NonNull final NavController navController) { |
||||
|
super.onCreateNavController(navController); |
||||
|
navController.getNavigatorProvider() |
||||
|
.addNavigator(new FragmentNavigatorWithDefaultAnimations(requireContext(), getChildFragmentManager(), getId())); |
||||
|
} |
||||
|
} |
@ -0,0 +1,100 @@ |
|||||
|
package awais.instagrabber.customviews.emoji; |
||||
|
|
||||
|
import android.app.Dialog; |
||||
|
import android.content.Context; |
||||
|
import android.os.Bundle; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.fragment.app.DialogFragment; |
||||
|
import androidx.fragment.app.Fragment; |
||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||
|
|
||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog; |
||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
|
||||
|
public class EmojiBottomSheetDialog extends BottomSheetDialogFragment { |
||||
|
public static final String TAG = EmojiBottomSheetDialog.class.getSimpleName(); |
||||
|
|
||||
|
private RecyclerView grid; |
||||
|
private EmojiPicker.OnEmojiClickListener callback; |
||||
|
|
||||
|
@NonNull |
||||
|
public static EmojiBottomSheetDialog newInstance() { |
||||
|
// Bundle args = new Bundle(); |
||||
|
// fragment.setArguments(args); |
||||
|
return new EmojiBottomSheetDialog(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onCreate(@Nullable final Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
setStyle(DialogFragment.STYLE_NORMAL, R.style.ThemeOverlay_Rounded_BottomSheetDialog); |
||||
|
} |
||||
|
|
||||
|
@Nullable |
||||
|
@Override |
||||
|
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { |
||||
|
final Context context = getContext(); |
||||
|
if (context == null) return null; |
||||
|
grid = new RecyclerView(context); |
||||
|
return grid; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { |
||||
|
init(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onStart() { |
||||
|
super.onStart(); |
||||
|
final Dialog dialog = getDialog(); |
||||
|
if (dialog == null) return; |
||||
|
final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog; |
||||
|
final View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); |
||||
|
if (bottomSheetInternal == null) return; |
||||
|
bottomSheetInternal.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; |
||||
|
bottomSheetInternal.requestLayout(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onAttach(@NonNull final Context context) { |
||||
|
super.onAttach(context); |
||||
|
final Fragment parentFragment = getParentFragment(); |
||||
|
if (parentFragment instanceof EmojiPicker.OnEmojiClickListener) { |
||||
|
callback = (EmojiPicker.OnEmojiClickListener) parentFragment; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onDestroyView() { |
||||
|
grid = null; |
||||
|
super.onDestroyView(); |
||||
|
} |
||||
|
|
||||
|
private void init() { |
||||
|
final Context context = getContext(); |
||||
|
if (context == null) return; |
||||
|
final GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 9); |
||||
|
grid.setLayoutManager(gridLayoutManager); |
||||
|
grid.setHasFixedSize(true); |
||||
|
grid.setClipToPadding(false); |
||||
|
grid.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(8))); |
||||
|
final EmojiGridAdapter adapter = new EmojiGridAdapter(null, (view, emoji) -> { |
||||
|
if (callback != null) { |
||||
|
callback.onClick(view, emoji); |
||||
|
} |
||||
|
dismiss(); |
||||
|
}, null); |
||||
|
grid.setAdapter(adapter); |
||||
|
} |
||||
|
} |
@ -1,163 +0,0 @@ |
|||||
package awais.instagrabber.customviews.emoji; |
|
||||
|
|
||||
import android.content.Context; |
|
||||
import android.graphics.Rect; |
|
||||
import android.view.Gravity; |
|
||||
import android.view.View; |
|
||||
import android.view.WindowManager.LayoutParams; |
|
||||
import android.widget.PopupWindow; |
|
||||
|
|
||||
import awais.instagrabber.R; |
|
||||
import awais.instagrabber.customviews.emoji.EmojiPicker.OnBackspaceClickListener; |
|
||||
import awais.instagrabber.customviews.emoji.EmojiPicker.OnEmojiClickListener; |
|
||||
import awais.instagrabber.utils.Utils; |
|
||||
|
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; |
|
||||
|
|
||||
/** |
|
||||
* https://stackoverflow.com/a/33897583/1436766 |
|
||||
*/ |
|
||||
public class EmojiPopupWindow extends PopupWindow { |
|
||||
|
|
||||
private int keyBoardHeight = 0; |
|
||||
private Boolean pendingOpen = false; |
|
||||
private Boolean isOpened = false; |
|
||||
private final View rootView; |
|
||||
private final Context context; |
|
||||
private final OnEmojiClickListener onEmojiClickListener; |
|
||||
private final OnBackspaceClickListener onBackspaceClickListener; |
|
||||
|
|
||||
private OnSoftKeyboardOpenCloseListener onSoftKeyboardOpenCloseListener; |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* Constructor |
|
||||
* |
|
||||
* @param rootView The top most layout in your view hierarchy. The difference of this view and the screen height will be used to calculate the keyboard height. |
|
||||
*/ |
|
||||
public EmojiPopupWindow(final View rootView, |
|
||||
final OnEmojiClickListener onEmojiClickListener, |
|
||||
final OnBackspaceClickListener onBackspaceClickListener) { |
|
||||
super(rootView.getContext()); |
|
||||
this.rootView = rootView; |
|
||||
this.context = rootView.getContext(); |
|
||||
this.onEmojiClickListener = onEmojiClickListener; |
|
||||
this.onBackspaceClickListener = onBackspaceClickListener; |
|
||||
View customView = createCustomView(); |
|
||||
setContentView(customView); |
|
||||
setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); |
|
||||
//default size |
|
||||
setSize((int) context.getResources().getDimension(R.dimen.keyboard_height), MATCH_PARENT); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Set the listener for the event of keyboard opening or closing. |
|
||||
*/ |
|
||||
public void setOnSoftKeyboardOpenCloseListener(OnSoftKeyboardOpenCloseListener listener) { |
|
||||
this.onSoftKeyboardOpenCloseListener = listener; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Use this function to show the emoji popup. |
|
||||
* NOTE: Since, the soft keyboard sizes are variable on different android devices, the |
|
||||
* library needs you to open the soft keyboard atleast once before calling this function. |
|
||||
* If that is not possible see showAtBottomPending() function. |
|
||||
*/ |
|
||||
public void showAtBottom() { |
|
||||
showAtLocation(rootView, Gravity.BOTTOM, 0, 0); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Use this function when the soft keyboard has not been opened yet. This |
|
||||
* will show the emoji popup after the keyboard is up next time. |
|
||||
* Generally, you will be calling InputMethodManager.showSoftInput function after |
|
||||
* calling this function. |
|
||||
*/ |
|
||||
public void showAtBottomPending() { |
|
||||
if (isKeyBoardOpen()) |
|
||||
showAtBottom(); |
|
||||
else |
|
||||
pendingOpen = true; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @return Returns true if the soft keyboard is open, false otherwise. |
|
||||
*/ |
|
||||
public Boolean isKeyBoardOpen() { |
|
||||
return isOpened; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Dismiss the popup |
|
||||
*/ |
|
||||
@Override |
|
||||
public void dismiss() { |
|
||||
super.dismiss(); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Call this function to resize the emoji popup according to your soft keyboard size |
|
||||
*/ |
|
||||
public void setSizeForSoftKeyboard() { |
|
||||
rootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> { |
|
||||
Rect r = new Rect(); |
|
||||
rootView.getWindowVisibleDisplayFrame(r); |
|
||||
|
|
||||
int screenHeight = getUsableScreenHeight(); |
|
||||
int heightDifference = screenHeight - (r.bottom - r.top); |
|
||||
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); |
|
||||
if (resourceId > 0) { |
|
||||
heightDifference -= context.getResources() |
|
||||
.getDimensionPixelSize(resourceId); |
|
||||
} |
|
||||
if (heightDifference > 100) { |
|
||||
keyBoardHeight = heightDifference; |
|
||||
setSize(MATCH_PARENT, keyBoardHeight); |
|
||||
if (!isOpened) { |
|
||||
if (onSoftKeyboardOpenCloseListener != null) |
|
||||
onSoftKeyboardOpenCloseListener.onKeyboardOpen(keyBoardHeight); |
|
||||
} |
|
||||
isOpened = true; |
|
||||
if (pendingOpen) { |
|
||||
showAtBottom(); |
|
||||
pendingOpen = false; |
|
||||
} |
|
||||
} else { |
|
||||
isOpened = false; |
|
||||
if (onSoftKeyboardOpenCloseListener != null) |
|
||||
onSoftKeyboardOpenCloseListener.onKeyboardClose(); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
private int getUsableScreenHeight() { |
|
||||
return Utils.displayMetrics.heightPixels; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Manually set the popup window size |
|
||||
* |
|
||||
* @param width Width of the popup |
|
||||
* @param height Height of the popup |
|
||||
*/ |
|
||||
public void setSize(int width, int height) { |
|
||||
setWidth(width); |
|
||||
setHeight(height); |
|
||||
} |
|
||||
|
|
||||
private View createCustomView() { |
|
||||
final EmojiPicker emojiPicker = new EmojiPicker(context); |
|
||||
final LayoutParams layoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT); |
|
||||
emojiPicker.setLayoutParams(layoutParams); |
|
||||
emojiPicker.init(rootView, onEmojiClickListener, onBackspaceClickListener); |
|
||||
return emojiPicker; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
public interface OnSoftKeyboardOpenCloseListener { |
|
||||
void onKeyboardOpen(int keyBoardHeight); |
|
||||
|
|
||||
void onKeyboardClose(); |
|
||||
} |
|
||||
} |
|
||||
|
|
@ -0,0 +1,320 @@ |
|||||
|
package awais.instagrabber.customviews.helpers; |
||||
|
|
||||
|
/* |
||||
|
* Copyright (C) 2013 The Android Open Source Project |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
|
||||
|
import android.animation.Animator; |
||||
|
import android.animation.AnimatorListenerAdapter; |
||||
|
import android.animation.AnimatorSet; |
||||
|
import android.animation.ValueAnimator; |
||||
|
import android.graphics.Color; |
||||
|
import android.util.Log; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.widget.EditText; |
||||
|
import android.widget.TextView; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.transition.Transition; |
||||
|
import androidx.transition.TransitionListenerAdapter; |
||||
|
import androidx.transition.TransitionValues; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
import awais.instagrabber.BuildConfig; |
||||
|
|
||||
|
/** |
||||
|
* This transition tracks changes to the text in TextView targets. If the text |
||||
|
* changes between the start and end scenes, the transition ensures that the |
||||
|
* starting text stays until the transition ends, at which point it changes |
||||
|
* to the end text. This is useful in situations where you want to resize a |
||||
|
* text view to its new size before displaying the text that goes there. |
||||
|
*/ |
||||
|
public class ChangeText extends Transition { |
||||
|
private static final String LOG_TAG = "TextChange"; |
||||
|
private static final String PROPNAME_TEXT = "android:textchange:text"; |
||||
|
private static final String PROPNAME_TEXT_SELECTION_START = |
||||
|
"android:textchange:textSelectionStart"; |
||||
|
private static final String PROPNAME_TEXT_SELECTION_END = |
||||
|
"android:textchange:textSelectionEnd"; |
||||
|
private static final String PROPNAME_TEXT_COLOR = "android:textchange:textColor"; |
||||
|
private int mChangeBehavior = CHANGE_BEHAVIOR_KEEP; |
||||
|
private boolean crossFade; |
||||
|
/** |
||||
|
* Flag specifying that the text in affected/changing TextView targets will keep |
||||
|
* their original text during the transition, setting it to the final text when |
||||
|
* the transition ends. This is the default behavior. |
||||
|
* |
||||
|
* @see #setChangeBehavior(int) |
||||
|
*/ |
||||
|
public static final int CHANGE_BEHAVIOR_KEEP = 0; |
||||
|
/** |
||||
|
* Flag specifying that the text changing animation should first fade |
||||
|
* out the original text completely. The new text is set on the target |
||||
|
* view at the end of the fade-out animation. This transition is typically |
||||
|
* used with a later {@link #CHANGE_BEHAVIOR_IN} transition, allowing more |
||||
|
* flexibility than the {@link #CHANGE_BEHAVIOR_OUT_IN} by allowing other |
||||
|
* transitions to be run sequentially or in parallel with these fades. |
||||
|
* |
||||
|
* @see #setChangeBehavior(int) |
||||
|
*/ |
||||
|
public static final int CHANGE_BEHAVIOR_OUT = 1; |
||||
|
/** |
||||
|
* Flag specifying that the text changing animation should fade in the |
||||
|
* end text into the affected target view(s). This transition is typically |
||||
|
* used in conjunction with an earlier {@link #CHANGE_BEHAVIOR_OUT} |
||||
|
* transition, possibly with other transitions running as well, such as |
||||
|
* a sequence to fade out, then resize the view, then fade in. |
||||
|
* |
||||
|
* @see #setChangeBehavior(int) |
||||
|
*/ |
||||
|
public static final int CHANGE_BEHAVIOR_IN = 2; |
||||
|
/** |
||||
|
* Flag specifying that the text changing animation should first fade |
||||
|
* out the original text completely and then fade in the |
||||
|
* new text. |
||||
|
* |
||||
|
* @see #setChangeBehavior(int) |
||||
|
*/ |
||||
|
public static final int CHANGE_BEHAVIOR_OUT_IN = 3; |
||||
|
private static final String[] sTransitionProperties = { |
||||
|
PROPNAME_TEXT, |
||||
|
PROPNAME_TEXT_SELECTION_START, |
||||
|
PROPNAME_TEXT_SELECTION_END |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Sets the type of changing animation that will be run, one of |
||||
|
* {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT}, |
||||
|
* {@link #CHANGE_BEHAVIOR_IN}, and {@link #CHANGE_BEHAVIOR_OUT_IN}. |
||||
|
* |
||||
|
* @param changeBehavior The type of fading animation to use when this |
||||
|
* transition is run. |
||||
|
* @return this textChange object. |
||||
|
*/ |
||||
|
public ChangeText setChangeBehavior(int changeBehavior) { |
||||
|
if (changeBehavior >= CHANGE_BEHAVIOR_KEEP && changeBehavior <= CHANGE_BEHAVIOR_OUT_IN) { |
||||
|
mChangeBehavior = changeBehavior; |
||||
|
} |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public ChangeText setCrossFade(final boolean crossFade) { |
||||
|
this.crossFade = crossFade; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getTransitionProperties() { |
||||
|
return sTransitionProperties; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Returns the type of changing animation that will be run. |
||||
|
* |
||||
|
* @return either {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT}, |
||||
|
* {@link #CHANGE_BEHAVIOR_IN}, or {@link #CHANGE_BEHAVIOR_OUT_IN}. |
||||
|
*/ |
||||
|
public int getChangeBehavior() { |
||||
|
return mChangeBehavior; |
||||
|
} |
||||
|
|
||||
|
private void captureValues(TransitionValues transitionValues) { |
||||
|
if (transitionValues.view instanceof TextView) { |
||||
|
TextView textview = (TextView) transitionValues.view; |
||||
|
transitionValues.values.put(PROPNAME_TEXT, textview.getText()); |
||||
|
if (textview instanceof EditText) { |
||||
|
transitionValues.values.put(PROPNAME_TEXT_SELECTION_START, |
||||
|
textview.getSelectionStart()); |
||||
|
transitionValues.values.put(PROPNAME_TEXT_SELECTION_END, |
||||
|
textview.getSelectionEnd()); |
||||
|
} |
||||
|
if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { |
||||
|
transitionValues.values.put(PROPNAME_TEXT_COLOR, textview.getCurrentTextColor()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void captureStartValues(@NonNull TransitionValues transitionValues) { |
||||
|
captureValues(transitionValues); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void captureEndValues(@NonNull TransitionValues transitionValues) { |
||||
|
captureValues(transitionValues); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Animator createAnimator(@NonNull ViewGroup sceneRoot, TransitionValues startValues, |
||||
|
TransitionValues endValues) { |
||||
|
if (startValues == null || endValues == null || |
||||
|
!(startValues.view instanceof TextView) || !(endValues.view instanceof TextView)) { |
||||
|
return null; |
||||
|
} |
||||
|
final TextView view = (TextView) endValues.view; |
||||
|
Map<String, Object> startVals = startValues.values; |
||||
|
Map<String, Object> endVals = endValues.values; |
||||
|
final CharSequence startText = startVals.get(PROPNAME_TEXT) != null ? |
||||
|
(CharSequence) startVals.get(PROPNAME_TEXT) : ""; |
||||
|
final CharSequence endText = endVals.get(PROPNAME_TEXT) != null ? |
||||
|
(CharSequence) endVals.get(PROPNAME_TEXT) : ""; |
||||
|
final int startSelectionStart, startSelectionEnd, endSelectionStart, endSelectionEnd; |
||||
|
if (view instanceof EditText) { |
||||
|
startSelectionStart = startVals.get(PROPNAME_TEXT_SELECTION_START) != null ? |
||||
|
(Integer) startVals.get(PROPNAME_TEXT_SELECTION_START) : -1; |
||||
|
startSelectionEnd = startVals.get(PROPNAME_TEXT_SELECTION_END) != null ? |
||||
|
(Integer) startVals.get(PROPNAME_TEXT_SELECTION_END) : startSelectionStart; |
||||
|
endSelectionStart = endVals.get(PROPNAME_TEXT_SELECTION_START) != null ? |
||||
|
(Integer) endVals.get(PROPNAME_TEXT_SELECTION_START) : -1; |
||||
|
endSelectionEnd = endVals.get(PROPNAME_TEXT_SELECTION_END) != null ? |
||||
|
(Integer) endVals.get(PROPNAME_TEXT_SELECTION_END) : endSelectionStart; |
||||
|
} else { |
||||
|
startSelectionStart = startSelectionEnd = endSelectionStart = endSelectionEnd = -1; |
||||
|
} |
||||
|
if (!Objects.equals(startText, endText)) { |
||||
|
final int startColor; |
||||
|
final int endColor; |
||||
|
if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { |
||||
|
view.setText(startText); |
||||
|
if (view instanceof EditText) { |
||||
|
setSelection(((EditText) view), startSelectionStart, startSelectionEnd); |
||||
|
} |
||||
|
} |
||||
|
Animator anim; |
||||
|
if (mChangeBehavior == CHANGE_BEHAVIOR_KEEP) { |
||||
|
startColor = endColor = 0; |
||||
|
anim = ValueAnimator.ofFloat(0, 1); |
||||
|
anim.addListener(new AnimatorListenerAdapter() { |
||||
|
@Override |
||||
|
public void onAnimationEnd(Animator animation) { |
||||
|
if (Objects.equals(startText, view.getText())) { |
||||
|
// Only set if it hasn't been changed since anim started |
||||
|
view.setText(endText); |
||||
|
if (view instanceof EditText) { |
||||
|
setSelection(((EditText) view), endSelectionStart, endSelectionEnd); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} else { |
||||
|
startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR); |
||||
|
endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR); |
||||
|
// Fade out start text |
||||
|
ValueAnimator outAnim = null, inAnim = null; |
||||
|
if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN || |
||||
|
mChangeBehavior == CHANGE_BEHAVIOR_OUT) { |
||||
|
outAnim = ValueAnimator.ofInt(Color.alpha(startColor), 0); |
||||
|
outAnim.addUpdateListener(animation -> { |
||||
|
int currAlpha = (Integer) animation.getAnimatedValue(); |
||||
|
view.setTextColor(currAlpha << 24 | startColor & 0xffffff); |
||||
|
}); |
||||
|
outAnim.addListener(new AnimatorListenerAdapter() { |
||||
|
@Override |
||||
|
public void onAnimationEnd(Animator animation) { |
||||
|
if (Objects.equals(startText, view.getText())) { |
||||
|
// Only set if it hasn't been changed since anim started |
||||
|
view.setText(endText); |
||||
|
if (view instanceof EditText) { |
||||
|
setSelection(((EditText) view), endSelectionStart, |
||||
|
endSelectionEnd); |
||||
|
} |
||||
|
} |
||||
|
// restore opaque alpha and correct end color |
||||
|
view.setTextColor(endColor); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN || |
||||
|
mChangeBehavior == CHANGE_BEHAVIOR_IN) { |
||||
|
inAnim = ValueAnimator.ofInt(0, Color.alpha(endColor)); |
||||
|
inAnim.addUpdateListener(animation -> { |
||||
|
int currAlpha = (Integer) animation.getAnimatedValue(); |
||||
|
view.setTextColor(currAlpha << 24 | endColor & 0xffffff); |
||||
|
}); |
||||
|
inAnim.addListener(new AnimatorListenerAdapter() { |
||||
|
@Override |
||||
|
public void onAnimationCancel(Animator animation) { |
||||
|
// restore opaque alpha and correct end color |
||||
|
view.setTextColor(endColor); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
if (outAnim != null && inAnim != null) { |
||||
|
anim = new AnimatorSet(); |
||||
|
final AnimatorSet animatorSet = (AnimatorSet) anim; |
||||
|
if (crossFade) { |
||||
|
animatorSet.playTogether(outAnim, inAnim); |
||||
|
} else { |
||||
|
animatorSet.playSequentially(outAnim, inAnim); |
||||
|
} |
||||
|
} else if (outAnim != null) { |
||||
|
anim = outAnim; |
||||
|
} else { |
||||
|
// Must be an in-only animation |
||||
|
anim = inAnim; |
||||
|
} |
||||
|
} |
||||
|
TransitionListener transitionListener = new TransitionListenerAdapter() { |
||||
|
int mPausedColor = 0; |
||||
|
|
||||
|
@Override |
||||
|
public void onTransitionPause(@NonNull Transition transition) { |
||||
|
if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { |
||||
|
view.setText(endText); |
||||
|
if (view instanceof EditText) { |
||||
|
setSelection(((EditText) view), endSelectionStart, endSelectionEnd); |
||||
|
} |
||||
|
} |
||||
|
if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { |
||||
|
mPausedColor = view.getCurrentTextColor(); |
||||
|
view.setTextColor(endColor); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onTransitionResume(@NonNull Transition transition) { |
||||
|
if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { |
||||
|
view.setText(startText); |
||||
|
if (view instanceof EditText) { |
||||
|
setSelection(((EditText) view), startSelectionStart, startSelectionEnd); |
||||
|
} |
||||
|
} |
||||
|
if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { |
||||
|
view.setTextColor(mPausedColor); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onTransitionEnd(Transition transition) { |
||||
|
transition.removeListener(this); |
||||
|
} |
||||
|
}; |
||||
|
addListener(transitionListener); |
||||
|
if (BuildConfig.DEBUG) { |
||||
|
Log.d(LOG_TAG, "createAnimator returning " + anim); |
||||
|
} |
||||
|
return anim; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private void setSelection(EditText editText, int start, int end) { |
||||
|
if (start >= 0 && end >= 0) { |
||||
|
editText.setSelection(start, end); |
||||
|
} |
||||
|
} |
||||
|
} |
1123
app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,91 @@ |
|||||
|
package awais.instagrabber.utils; |
||||
|
|
||||
|
/* |
||||
|
* Copyright (C) 2009 The Android Open Source Project |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.core.util.ObjectsCompat; |
||||
|
|
||||
|
/** |
||||
|
* Container to ease passing around a tuple of two objects. This object provides a sensible |
||||
|
* implementation of equals(), returning true if equals() is true on each of the contained |
||||
|
* objects. |
||||
|
*/ |
||||
|
public class NullSafePair<F, S> { |
||||
|
public final @NonNull |
||||
|
F first; |
||||
|
public final @NonNull |
||||
|
S second; |
||||
|
|
||||
|
/** |
||||
|
* Constructor for a Pair. |
||||
|
* |
||||
|
* @param first the first object in the Pair |
||||
|
* @param second the second object in the pair |
||||
|
*/ |
||||
|
public NullSafePair(@NonNull F first, @NonNull S second) { |
||||
|
this.first = first; |
||||
|
this.second = second; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Checks the two objects for equality by delegating to their respective |
||||
|
* {@link Object#equals(Object)} methods. |
||||
|
* |
||||
|
* @param o the {@link androidx.core.util.Pair} to which this one is to be checked for equality |
||||
|
* @return true if the underlying objects of the Pair are both considered |
||||
|
* equal |
||||
|
*/ |
||||
|
@Override |
||||
|
public boolean equals(Object o) { |
||||
|
if (!(o instanceof androidx.core.util.Pair)) { |
||||
|
return false; |
||||
|
} |
||||
|
androidx.core.util.Pair<?, ?> p = (androidx.core.util.Pair<?, ?>) o; |
||||
|
return ObjectsCompat.equals(p.first, first) && ObjectsCompat.equals(p.second, second); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Compute a hash code using the hash codes of the underlying objects |
||||
|
* |
||||
|
* @return a hashcode of the Pair |
||||
|
*/ |
||||
|
@Override |
||||
|
public int hashCode() { |
||||
|
return first.hashCode() ^ second.hashCode(); |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "Pair{" + first + " " + second + "}"; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Convenience method for creating an appropriately typed pair. |
||||
|
* |
||||
|
* @param a the first object in the Pair |
||||
|
* @param b the second object in the pair |
||||
|
* @return a Pair that is templatized with the types of a and b |
||||
|
*/ |
||||
|
@NonNull |
||||
|
public static <A, B> androidx.core.util.Pair<A, B> create(@Nullable A a, @Nullable B b) { |
||||
|
return new androidx.core.util.Pair<A, B>(a, b); |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<translate |
||||
|
android:duration="@android:integer/config_mediumAnimTime" |
||||
|
android:fromXDelta="50%p" |
||||
|
android:toXDelta="0" /> |
||||
|
<alpha |
||||
|
android:duration="@android:integer/config_mediumAnimTime" |
||||
|
android:fromAlpha="0.0" |
||||
|
android:toAlpha="1.0" /> |
||||
|
</set> |
@ -1,10 +1,5 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" |
<translate xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shareInterpolator="false"> |
|
||||
<translate |
|
||||
android:duration="300" |
android:duration="300" |
||||
android:fromXDelta="100%" |
android:fromXDelta="100%" |
||||
android:fromYDelta="0%" |
android:toXDelta="0%" /> |
||||
android:toXDelta="0%" |
|
||||
android:toYDelta="0%" /> |
|
||||
</set> |
|
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<translate |
||||
|
android:duration="@android:integer/config_mediumAnimTime" |
||||
|
android:fromXDelta="0" |
||||
|
android:toXDelta="-50%p" /> |
||||
|
<alpha |
||||
|
android:duration="@android:integer/config_mediumAnimTime" |
||||
|
android:fromAlpha="1.0" |
||||
|
android:toAlpha="0.0" /> |
||||
|
</set> |
@ -1,10 +1,5 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" |
<translate xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shareInterpolator="false"> |
|
||||
<translate |
|
||||
android:duration="300" |
android:duration="300" |
||||
android:fromXDelta="0%" |
android:fromXDelta="0%" |
||||
android:fromYDelta="0%" |
android:toXDelta="100%" /> |
||||
android:toXDelta="100%" |
|
||||
android:toYDelta="0%" /> |
|
||||
</set> |
|
@ -1,10 +1,10 @@ |
|||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
android:width="24dp" |
||||
android:height="24dp" |
android:height="24dp" |
||||
|
android:tint="?colorControlNormal" |
||||
android:viewportWidth="24" |
android:viewportWidth="24" |
||||
android:viewportHeight="24" |
android:viewportHeight="24"> |
||||
android:tint="#333333"> |
|
||||
<path |
<path |
||||
android:fillColor="@android:color/white" |
android:fillColor="@android:color/white" |
||||
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/> |
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z" /> |
||||
</vector> |
</vector> |
@ -0,0 +1,10 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24" |
||||
|
android:tint="?attr/colorControlNormal"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M17,3L7,3c-1.1,0 -2,0.9 -2,2v16l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,6c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v12z"/> |
||||
|
</vector> |
@ -0,0 +1,10 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24" |
||||
|
android:tint="?attr/colorControlNormal"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M3,17.46v3.04c0,0.28 0.22,0.5 0.5,0.5h3.04c0.13,0 0.26,-0.05 0.35,-0.15L17.81,9.94l-3.75,-3.75L3.15,17.1c-0.1,0.1 -0.15,0.22 -0.15,0.36zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> |
||||
|
</vector> |
@ -1,5 +1,5 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
android:shape="oval"> |
||||
<solid android:color="@color/black" /> |
<solid android:color="@android:color/transparent" /> |
||||
</shape> |
</shape> |
@ -1,40 +1,39 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" |
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
android:layout_height="match_parent" |
||||
android:background="?attr/colorSurface"> |
android:background="?attr/colorSurface" |
||||
|
app:layoutDescription="@xml/header_list_scene"> |
||||
|
|
||||
<!--<com.google.android.material.appbar.AppBarLayout--> |
<androidx.recyclerview.widget.RecyclerView |
||||
<!-- android:id="@+id/stories_container"--> |
android:id="@+id/header" |
||||
<!-- android:layout_width="match_parent"--> |
android:layout_width="match_parent" |
||||
<!-- android:layout_height="wrap_content">--> |
android:layout_height="wrap_content" |
||||
|
android:background="?attr/toolbarColor" |
||||
<!-- <com.google.android.material.appbar.CollapsingToolbarLayout--> |
android:clipToPadding="false" |
||||
<!-- android:layout_width="match_parent"--> |
android:orientation="horizontal" |
||||
<!-- android:layout_height="wrap_content"--> |
app:layout_constraintBottom_toTopOf="@id/feed_swipe_refresh_layout" |
||||
<!-- app:layout_scrollFlags="scroll|snap">--> |
app:layout_constraintTop_toTopOf="parent" |
||||
|
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" |
||||
<!--<androidx.recyclerview.widget.RecyclerView--> |
tools:listitem="@layout/item_highlight" /> |
||||
<!-- android:id="@+id/feed_stories_recycler_view"--> |
|
||||
<!-- android:layout_width="match_parent"--> |
|
||||
<!-- android:layout_height="wrap_content"--> |
|
||||
<!-- android:clipToPadding="false" />--> |
|
||||
<!-- </com.google.android.material.appbar.CollapsingToolbarLayout>--> |
|
||||
<!--</com.google.android.material.appbar.AppBarLayout>--> |
|
||||
|
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout |
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout |
||||
android:id="@+id/feed_swipe_refresh_layout" |
android:id="@+id/feed_swipe_refresh_layout" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
android:layout_height="0dp" |
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"> |
android:clipToPadding="false" |
||||
|
android:paddingBottom="?attr/actionBarSize" |
||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" |
||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@id/header"> |
||||
|
|
||||
<awais.instagrabber.customviews.PostsRecyclerView |
<awais.instagrabber.customviews.PostsRecyclerView |
||||
android:id="@+id/feed_recycler_view" |
android:id="@+id/feed_recycler_view" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
android:layout_height="match_parent" |
||||
android:clipToPadding="false" |
android:clipToPadding="false" |
||||
tools:listitem="@layout/item_feed_photo" /> |
tools:listitem="@layout/item_feed_grid" /> |
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
</androidx.constraintlayout.motion.widget.MotionLayout> |
@ -0,0 +1,208 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> |
||||
|
|
||||
|
<androidx.constraintlayout.widget.Barrier |
||||
|
android:id="@+id/buttons_top_barrier" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
app:barrierAllowsGoneWidgets="true" |
||||
|
app:barrierDirection="bottom" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/like" |
||||
|
style="@style/Widget.MaterialComponents.Button.TextButton" |
||||
|
android:layout_width="36dp" |
||||
|
android:layout_height="40dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
android:visibility="visible" |
||||
|
app:icon="@drawable/ic_not_liked" |
||||
|
app:iconGravity="textStart" |
||||
|
app:iconPadding="0dp" |
||||
|
app:iconSize="22dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/likes_count" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" |
||||
|
app:layout_constraintVertical_bias="0" |
||||
|
app:layout_constraintVertical_chainStyle="packed" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
<awais.instagrabber.customviews.FormattedNumberTextView |
||||
|
android:id="@+id/likes_count" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="0dp" |
||||
|
android:layout_marginEnd="0dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
android:gravity="center_vertical" |
||||
|
android:maxWidth="100dp" |
||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" |
||||
|
android:textColor="?android:attr/textColorSecondary" |
||||
|
app:layout_constraintBottom_toBottomOf="@id/like" |
||||
|
app:layout_constraintEnd_toStartOf="@id/comment" |
||||
|
app:layout_constraintStart_toEndOf="@id/like" |
||||
|
app:layout_constraintTop_toTopOf="@id/like" |
||||
|
tools:text="9.9k" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/comment" |
||||
|
style="@style/Widget.MaterialComponents.Button.TextButton" |
||||
|
android:layout_width="36dp" |
||||
|
android:layout_height="40dp" |
||||
|
android:layout_marginStart="8dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
app:icon="@drawable/ic_outline_comments_24" |
||||
|
app:iconPadding="0dp" |
||||
|
app:iconSize="22dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/comments_count" |
||||
|
app:layout_constraintStart_toEndOf="@id/likes_count" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" /> |
||||
|
|
||||
|
<awais.instagrabber.customviews.FormattedNumberTextView |
||||
|
android:id="@+id/comments_count" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="0dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
android:ellipsize="end" |
||||
|
android:gravity="center_vertical" |
||||
|
android:maxWidth="100dp" |
||||
|
android:maxLines="1" |
||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" |
||||
|
android:textColor="?android:attr/textColorSecondary" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/space_1" |
||||
|
app:layout_constraintStart_toEndOf="@id/comment" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" |
||||
|
tools:text="9999999999999999999999999999999999999999" /> |
||||
|
|
||||
|
<Space |
||||
|
android:id="@+id/space_1" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="0dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/share" |
||||
|
app:layout_constraintStart_toEndOf="@id/comments_count" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/share" |
||||
|
style="@style/Widget.MaterialComponents.Button.TextButton" |
||||
|
android:layout_width="48dp" |
||||
|
android:layout_height="40dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
app:icon="?attr/actionModeShareDrawable" |
||||
|
app:iconGravity="textStart" |
||||
|
app:iconPadding="0dp" |
||||
|
app:iconSize="18dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/save" |
||||
|
app:layout_constraintStart_toEndOf="@id/space_1" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/save" |
||||
|
style="@style/Widget.MaterialComponents.Button.TextButton" |
||||
|
android:layout_width="48dp" |
||||
|
android:layout_height="40dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
android:visibility="visible" |
||||
|
app:icon="@drawable/ic_round_bookmark_border_24" |
||||
|
app:iconGravity="textStart" |
||||
|
app:iconPadding="0dp" |
||||
|
app:iconSize="18dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/download" |
||||
|
app:layout_constraintStart_toEndOf="@id/share" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/download" |
||||
|
style="@style/Widget.MaterialComponents.Button.TextButton" |
||||
|
android:layout_width="48dp" |
||||
|
android:layout_height="40dp" |
||||
|
android:background="@drawable/background_grey_ripple" |
||||
|
android:visibility="visible" |
||||
|
app:icon="@drawable/ic_download" |
||||
|
app:iconGravity="textStart" |
||||
|
app:iconPadding="0dp" |
||||
|
app:iconSize="18dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/buttons_bottom_barrier" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toEndOf="@id/save" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_top_barrier" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
<androidx.constraintlayout.widget.Barrier |
||||
|
android:id="@+id/buttons_bottom_barrier" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="0dp" |
||||
|
app:barrierAllowsGoneWidgets="true" |
||||
|
app:barrierDirection="top" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/date" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:padding="8dp" |
||||
|
app:layout_constraintBottom_toTopOf="@id/caption_barrier" |
||||
|
app:layout_constraintEnd_toStartOf="@id/views_count" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@id/buttons_bottom_barrier" |
||||
|
tools:layout_constraintVertical_chainStyle="packed" |
||||
|
tools:text="2020-11-07 11:18:55" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/views_count" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:padding="8dp" |
||||
|
app:layout_constraintBottom_toBottomOf="@id/date" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toEndOf="@id/date" |
||||
|
app:layout_constraintTop_toTopOf="@id/date" |
||||
|
tools:text="9999999999 views" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
<androidx.constraintlayout.widget.Barrier |
||||
|
android:id="@+id/caption_barrier" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="0dp" |
||||
|
app:barrierAllowsGoneWidgets="true" |
||||
|
app:barrierDirection="bottom" /> |
||||
|
|
||||
|
<awais.instagrabber.customviews.RamboTextViewV2 |
||||
|
android:id="@+id/caption" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="bottom" |
||||
|
android:background="@null" |
||||
|
android:clickable="true" |
||||
|
android:focusable="true" |
||||
|
android:padding="8dp" |
||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" |
||||
|
app:layout_constraintBottom_toTopOf="@id/translate" |
||||
|
app:layout_constraintTop_toBottomOf="@id/caption_barrier" |
||||
|
app:layout_constraintVertical_bias="0" |
||||
|
app:layout_constraintVertical_chainStyle="packed" |
||||
|
tools:text="Text text text Text text text Text text text Text text text Text text text" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/translate" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:background="@null" |
||||
|
android:gravity="center_vertical" |
||||
|
android:padding="8dp" |
||||
|
android:text="@string/translate_caption" |
||||
|
android:textColor="@color/blue_600" |
||||
|
android:textSize="16sp" |
||||
|
android:visibility="visible" |
||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@id/caption" /> |
||||
|
</merge> |
@ -0,0 +1,5 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<resources> |
||||
|
<!--<drawable name="exo_styled_controls_play">@drawable/ic_play_arrow_24</drawable>--> |
||||
|
<!--<drawable name="exo_styled_controls_pause">@drawable/ic_pause_24</drawable>--> |
||||
|
</resources> |
Some files were not shown because too many files changed in this diff
Reference in new issue
xxxxxxxxxx