1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-12-26 22:56:58 +00:00

Merge branch 'master' into stamatiap/development

This commit is contained in:
Stamatia Papageorgiou 2021-05-10 22:25:07 +03:00 committed by GitHub
commit d9248d2fb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 2964 additions and 2394 deletions

View File

@ -23,10 +23,10 @@ jobs:
run: chmod +x gradlew
- name: Build Github unsigned apk
run: ./gradlew assembleGithubRelease --stacktrace --project-prop pre
run: ./gradlew assembleGithubRelease --stacktrace --project-prop pre --project-prop split
- name: Sign APK
uses: r0adkll/sign-android-release@v1
uses: ammargitham/sign-android-release@v1.1.1
# ID used to access action output
id: sign_app
with:
@ -45,7 +45,8 @@ jobs:
uses: actions/upload-artifact@v2
with:
name: barinsta_nightly_${{ steps.date.outputs.date }}
path: ${{steps.sign_app.outputs.signedReleaseFile}}
# path: ${{steps.sign_app.outputs.signedReleaseFile}}
path: app/build/outputs/apk/github/release/*-signed.apk
# Send success notification
- name: Send success Telegram notification
@ -55,7 +56,8 @@ jobs:
to: ${{ secrets.TELEGRAM_BUILDS_CHANNEL_TO }}
token: ${{ secrets.TELEGRAM_BUILDS_BOT_TOKEN }}
message: "${{ github.workflow }} ${{ github.job }} #${{ github.run_number }} completed successfully.\nhttps://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
document: ${{steps.sign_app.outputs.signedReleaseFile}}
# document: ${{steps.sign_app.outputs.signedReleaseFile}}
document: app/build/outputs/apk/github/release/*-signed.apk
# Send failure notification
- name: Send failure Telegram notification

View File

@ -14,20 +14,20 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build Github unsigned pre-release apk
run: ./gradlew assembleGithubRelease --stacktrace --project-prop pre
run: ./gradlew assembleGithubRelease --stacktrace --project-prop pre --project-prop split
- name: Sign APK
uses: r0adkll/sign-android-release@v1
uses: ammargitham/sign-android-release@v1.1.1
# ID used to access action output
id: sign_app
with:
@ -36,18 +36,19 @@ jobs:
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
- name: Get current date and time
id: date
run: echo "::set-output name=date::$(date +'%Y%m%d_%H%M%S')"
# Create artifact
# Create artifact
- name: Create apk artifact
uses: actions/upload-artifact@v2
with:
name: barinsta_pre-release_${{ steps.date.outputs.date }}
path: ${{steps.sign_app.outputs.signedReleaseFile}}
# path: ${{steps.sign_app.outputs.signedReleaseFile}}
path: app/build/outputs/apk/github/release/*-signed.apk
# Send success notification
- name: Send success Telegram notification
if: ${{ success() }}
@ -56,8 +57,9 @@ jobs:
to: ${{ secrets.TELEGRAM_BUILDS_CHANNEL_TO }}
token: ${{ secrets.TELEGRAM_BUILDS_BOT_TOKEN }}
message: "${{ github.workflow }} ${{ github.job }} #${{ github.run_number }} completed successfully.\nURL: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
document: ${{steps.sign_app.outputs.signedReleaseFile}}
# document: ${{steps.sign_app.outputs.signedReleaseFile}}
document: app/build/outputs/apk/github/release/*-signed.apk
# Send failure notification
- name: Send failure Telegram notification
if: ${{ failure() }}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
<bytecodeTargetLevel target="11" />
</component>
</project>

View File

@ -7,7 +7,6 @@
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View File

@ -40,7 +40,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@ -3,6 +3,7 @@
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />

View File

@ -82,6 +82,27 @@ android {
}
}
splits {
// Configures multiple APKs based on ABI.
abi {
// Enables building multiple APKs per ABI.
enable project.hasProperty("split") && !gradle.startParameter.taskNames.isEmpty() && gradle.startParameter.taskNames.get(0).contains('Release')
// By default all ABIs are included, so use reset() and include to specify that we only
// want APKs for x86 and x86_64.
// Resets the list of ABIs that Gradle should create APKs for to none.
reset()
// Specifies a list of ABIs that Gradle should create APKs for.
include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"
// Specifies that we want to also generate a universal APK that includes all ABIs.
universalApk true
}
}
android.applicationVariants.all { variant ->
if (variant.flavorName != "github") return
variant.outputs.all { output ->
@ -90,15 +111,32 @@ android {
// def versionCode = variant.versionCode
def flavor = variant.flavorName
def suffix = "${versionName}-${flavor}_${builtType}" // eg. 19.1.0-github_debug or release
def flavorBuiltType = "${flavor}_${builtType}"
def suffix
// For x86 and x86_64, the versionNames are already overridden
if (versionName.contains(flavorBuiltType)) {
suffix = "${versionName}"
} else {
suffix = "${versionName}-${flavorBuiltType}" // eg. 19.1.0-github_debug or release
}
if (builtType.toString() == 'release' && project.hasProperty("pre")) {
buildConfigField("boolean", "isPre", "true")
// append latest commit short hash for pre-release
suffix = "${versionName}.${getGitHash()}-${flavor}" // eg. 19.1.0.b123456-github
flavorBuiltType = "${getGitHash()}-${flavor}"
// For x86 and x86_64, the versionNames are already overridden
if (versionName.contains(flavorBuiltType)) {
suffix = "${versionName}"
} else {
// append latest commit short hash for pre-release
suffix = "${versionName}.${flavorBuiltType}" // eg. 19.1.0.b123456-github
}
}
output.versionNameOverride = suffix
outputFileName = "barinsta_${suffix}.apk"
def abi = output.getFilter(com.android.build.OutputFile.ABI)
// println(abi + ", " + versionName + ", " + flavor + ", " + builtType + ", " + suffix)
outputFileName = abi == null ? "barinsta_${suffix}.apk" : "barinsta_${suffix}_${abi}.apk"
}
}
@ -118,10 +156,10 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
def appcompat_version = "1.2.0"
def nav_version = '2.3.4'
def nav_version = '2.3.5'
def exoplayer_version = '2.13.3'
implementation 'com.google.android.material:material:1.4.0-alpha02'
implementation 'com.google.android.material:material:1.4.0-beta01'
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version"
@ -129,7 +167,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
implementation "androidx.recyclerview:recyclerview:1.2.0-rc01"
implementation "androidx.recyclerview:recyclerview:1.2.0"
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation "androidx.navigation:navigation-fragment:$nav_version"
@ -169,6 +207,8 @@ dependencies {
implementation 'org.apache.commons:commons-imaging:1.0-alpha2'
implementation 'com.github.skydoves:balloon:1.3.4'
implementation 'com.github.ammargitham:AutoLinkTextViewV2:v3.1.0'
implementation 'com.github.ammargitham:uCrop:2.3-native-beta-2'
implementation 'com.github.ammargitham:android-gpuimage:2.1.1-beta4'

View File

@ -335,6 +335,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
} catch (Exception e) {
Log.e(TAG, "onDestroy: ", e);
}
instance = null;
}
@Override
@ -504,11 +505,12 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
setupMenu(backStack.size(), destinationId);
final boolean contains = showBottomViewDestinations.contains(destinationId);
binding.bottomNavView.setVisibility(contains ? View.VISIBLE : View.GONE);
if (contains && behavior != null) {
behavior.slideUp(binding.bottomNavView);
}
binding.getRoot().post(() -> {
binding.bottomNavView.setVisibility(contains ? View.VISIBLE : View.GONE);
if (contains && behavior != null) {
behavior.slideUp(binding.bottomNavView);
}
});
// explicitly hide keyboard when we navigate
final View view = getCurrentFocus();
Utils.hideKeyboard(view);
@ -651,7 +653,11 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
if (navController == null) return;
final Bundle bundle = new Bundle();
bundle.putString("username", "@" + username);
navController.navigate(R.id.action_global_profileFragment, bundle);
try {
navController.navigate(R.id.action_global_profileFragment, bundle);
} catch (Exception e) {
Log.e(TAG, "showProfileView: ", e);
}
}
private void showPostView(@NonNull final IntentModel intentModel) {
@ -664,11 +670,16 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
alertDialog.show();
new PostFetcher(shortCode, feedModel -> {
if (feedModel != null) {
final PostViewV2Fragment fragment = PostViewV2Fragment
.builder(feedModel)
.build();
fragment.setOnShowListener(dialog -> alertDialog.dismiss());
fragment.show(getSupportFragmentManager(), "post_view");
if (currentNavControllerLiveData == null) return;
final NavController navController = currentNavControllerLiveData.getValue();
if (navController == null) return;
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "showPostView: ", e);
}
return;
}
Toast.makeText(getApplicationContext(), R.string.post_not_found, Toast.LENGTH_SHORT).show();
@ -724,11 +735,19 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
}
public void setCollapsingView(@NonNull final View view) {
binding.collapsingToolbarLayout.addView(view, 0);
try {
binding.collapsingToolbarLayout.addView(view, 0);
} catch (Exception e) {
Log.e(TAG, "setCollapsingView: ", e);
}
}
public void removeCollapsingView(@NonNull final View view) {
binding.collapsingToolbarLayout.removeView(view);
try {
binding.collapsingToolbarLayout.removeView(view);
} catch (Exception e) {
Log.e(TAG, "removeCollapsingView: ", e);
}
}
public void setToolbar(final Toolbar toolbar) {

View File

@ -406,6 +406,8 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
void onReactionClick(DirectItem item, int position);
void onOptionSelect(DirectItem item, @IdRes int itemId, final Function<DirectItem, Void> callback);
void onAddReactionListener(DirectItem item);
}
public interface DirectItemInternalLongClickListener {

View File

@ -1,11 +1,17 @@
package awais.instagrabber.adapters;
import android.view.View;
import com.google.android.exoplayer2.ui.StyledPlayerView;
import awais.instagrabber.repositories.responses.Media;
public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback {
@Override
public void onThumbnailLoaded(final int position) {}
@Override
public void onItemClicked(final int position) {}
public void onItemClicked(final int position, final Media media, final View view) {}
@Override
public void onPlayerPlay(final int position) {}
@ -15,4 +21,12 @@ public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback
@Override
public void onPlayerRelease(final int position) {}
@Override
public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) {}
@Override
public boolean isInFullScreen() {
return false;
}
}

View File

@ -1,16 +1,18 @@
package awais.instagrabber.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import com.google.android.exoplayer2.ui.StyledPlayerView;
import awais.instagrabber.adapters.viewholder.SliderItemViewHolder;
import awais.instagrabber.adapters.viewholder.SliderPhotoViewHolder;
import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder;
import awais.instagrabber.customviews.VerticalDragHelper;
import awais.instagrabber.databinding.ItemSliderPhotoBinding;
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
import awais.instagrabber.models.enums.MediaItemType;
@ -18,10 +20,8 @@ import awais.instagrabber.repositories.responses.Media;
public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewHolder> {
private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener;
private final boolean loadVideoOnItemClick;
private final SliderCallback sliderCallback;
// private final LayoutExoCustomControlsBinding controlsBinding;
private static final DiffUtil.ItemCallback<Media> DIFF_CALLBACK = new DiffUtil.ItemCallback<Media>() {
@Override
@ -35,15 +35,11 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
}
};
public SliderItemsAdapter(final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener,
// final LayoutExoCustomControlsBinding controlsBinding,
final boolean loadVideoOnItemClick,
public SliderItemsAdapter(final boolean loadVideoOnItemClick,
final SliderCallback sliderCallback) {
super(DIFF_CALLBACK);
this.onVerticalDragListener = onVerticalDragListener;
this.loadVideoOnItemClick = loadVideoOnItemClick;
this.sliderCallback = sliderCallback;
// this.controlsBinding = controlsBinding;
}
@NonNull
@ -54,12 +50,12 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
switch (mediaItemType) {
case MEDIA_TYPE_VIDEO: {
final LayoutVideoPlayerWithThumbnailBinding binding = LayoutVideoPlayerWithThumbnailBinding.inflate(inflater, parent, false);
return new SliderVideoViewHolder(binding, onVerticalDragListener, loadVideoOnItemClick);
return new SliderVideoViewHolder(binding, loadVideoOnItemClick);
}
case MEDIA_TYPE_IMAGE:
default:
final ItemSliderPhotoBinding binding = ItemSliderPhotoBinding.inflate(inflater, parent, false);
return new SliderPhotoViewHolder(binding, onVerticalDragListener);
return new SliderPhotoViewHolder(binding);
}
}
@ -142,12 +138,16 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
public interface SliderCallback {
void onThumbnailLoaded(int position);
void onItemClicked(int position);
void onItemClicked(int position, final Media media, final View view);
void onPlayerPlay(int position);
void onPlayerPause(int position);
void onPlayerRelease(int position);
void onFullScreenModeChanged(boolean isFullScreen, final StyledPlayerView playerView);
boolean isInFullScreen();
}
}

View File

@ -2,7 +2,6 @@ package awais.instagrabber.adapters.viewholder;
import android.graphics.drawable.Animatable;
import android.net.Uri;
import android.view.GestureDetector;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
@ -14,8 +13,8 @@ import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import awais.instagrabber.adapters.SliderItemsAdapter;
import awais.instagrabber.customviews.VerticalDragHelper;
import awais.instagrabber.customviews.drawee.AnimatedZoomableController;
import awais.instagrabber.customviews.drawee.DoubleTapGestureListener;
import awais.instagrabber.databinding.ItemSliderPhotoBinding;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.utils.ResponseBodyUtils;
@ -24,13 +23,10 @@ public class SliderPhotoViewHolder extends SliderItemViewHolder {
private static final String TAG = "FeedSliderPhotoViewHolder";
private final ItemSliderPhotoBinding binding;
private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener;
public SliderPhotoViewHolder(@NonNull final ItemSliderPhotoBinding binding,
final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener) {
public SliderPhotoViewHolder(@NonNull final ItemSliderPhotoBinding binding) {
super(binding.getRoot());
this.binding = binding;
this.onVerticalDragListener = onVerticalDragListener;
}
public void bind(@NonNull final Media model,
@ -62,74 +58,19 @@ public class SliderPhotoViewHolder extends SliderItemViewHolder {
})
.setLowResImageRequest(ImageRequest.fromUri(ResponseBodyUtils.getThumbUrl(model)))
.build());
// binding.getRoot().setOnClickListener(v -> {
// if (sliderCallback != null) {
// sliderCallback.onItemClicked(position);
// }
// });
binding.getRoot().setTapListener(new GestureDetector.SimpleOnGestureListener() {
final DoubleTapGestureListener tapListener = new DoubleTapGestureListener(binding.getRoot()) {
@Override
public boolean onSingleTapUp(final MotionEvent e) {
public boolean onSingleTapConfirmed(final MotionEvent e) {
if (sliderCallback != null) {
sliderCallback.onItemClicked(position);
return true;
sliderCallback.onItemClicked(position, model, binding.getRoot());
}
return false;
return super.onSingleTapConfirmed(e);
}
});
};
binding.getRoot().setTapListener(tapListener);
final AnimatedZoomableController zoomableController = AnimatedZoomableController.newInstance();
zoomableController.setMaxScaleFactor(3f);
binding.getRoot().setZoomableController(zoomableController);
if (onVerticalDragListener != null) {
binding.getRoot().setOnVerticalDragListener(onVerticalDragListener);
}
binding.getRoot().setZoomingEnabled(true);
}
// private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) {
// final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams();
// final int deviceWidth = Utils.displayMetrics.widthPixels;
// final int spanWidth = deviceWidth / spanCount;
// final int spanHeight = NumberUtils.getResultingHeight(spanWidth, feedModel.getImageHeight(), feedModel.getImageWidth());
// final int width = spanWidth == 0 ? deviceWidth : spanWidth;
// final int height = spanHeight == 0 ? deviceWidth + 1 : spanHeight;
// if (animate) {
// Animation animation = AnimationUtils.expand(
// binding.imageViewer,
// layoutParams.width,
// layoutParams.height,
// width,
// height,
// new Animation.AnimationListener() {
// @Override
// public void onAnimationStart(final Animation animation) {
// showOrHideDetails(spanCount);
// }
//
// @Override
// public void onAnimationEnd(final Animation animation) {
// // showOrHideDetails(spanCount);
// }
//
// @Override
// public void onAnimationRepeat(final Animation animation) {
//
// }
// });
// binding.imageViewer.startAnimation(animation);
// } else {
// layoutParams.width = width;
// layoutParams.height = height;
// binding.imageViewer.requestLayout();
// }
// }
//
// private void showOrHideDetails(final int spanCount) {
// if (spanCount == 1) {
// binding.itemFeedTop.getRoot().setVisibility(View.VISIBLE);
// binding.itemFeedBottom.getRoot().setVisibility(View.VISIBLE);
// } else {
// binding.itemFeedTop.getRoot().setVisibility(View.GONE);
// binding.itemFeedBottom.getRoot().setVisibility(View.GONE);
// }
// }
}

View File

@ -7,10 +7,11 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.google.android.exoplayer2.ui.StyledPlayerView;
import java.util.List;
import awais.instagrabber.adapters.SliderItemsAdapter;
import awais.instagrabber.customviews.VerticalDragHelper;
import awais.instagrabber.customviews.VideoPlayerCallbackAdapter;
import awais.instagrabber.customviews.VideoPlayerViewHelper;
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
@ -27,40 +28,23 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
private static final String TAG = "SliderVideoViewHolder";
private final LayoutVideoPlayerWithThumbnailBinding binding;
// private final LayoutExoCustomControlsBinding controlsBinding;
private final boolean loadVideoOnItemClick;
private final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(final MotionEvent e) {
binding.playerView.performClick();
return true;
}
};
private VideoPlayerViewHelper videoPlayerViewHelper;
@SuppressLint("ClickableViewAccessibility")
public SliderVideoViewHolder(@NonNull final LayoutVideoPlayerWithThumbnailBinding binding,
final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener,
// final LayoutExoCustomControlsBinding controlsBinding,
final boolean loadVideoOnItemClick) {
super(binding.getRoot());
this.binding = binding;
// this.controlsBinding = controlsBinding;
this.loadVideoOnItemClick = loadVideoOnItemClick;
// if (onVerticalDragListener != null) {
// final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent);
// final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.playerView);
// thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
// playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
// binding.thumbnailParent.setOnTouchListener((v, event) -> {
// final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event);
// if (onDragTouch) {
// return true;
// }
// return thumbnailVerticalDragHelper.onGestureTouchEvent(event);
// });
// }
final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(final MotionEvent e) {
binding.playerView.performClick();
return true;
}
};
final GestureDetector gestureDetector = new GestureDetector(itemView.getContext(), videoPlayerViewGestureListener);
binding.playerView.setOnTouchListener((v, event) -> {
gestureDetector.onTouchEvent(event);
@ -77,7 +61,7 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
@Override
public void onThumbnailClick() {
if (sliderCallback != null) {
sliderCallback.onItemClicked(position);
sliderCallback.onItemClicked(position, media, binding.getRoot());
}
}
@ -120,6 +104,21 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
sliderCallback.onPlayerRelease(position);
}
}
@Override
public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) {
if (sliderCallback != null) {
sliderCallback.onFullScreenModeChanged(isFullScreen, playerView);
}
}
@Override
public boolean isInFullScreen() {
if (sliderCallback != null) {
return sliderCallback.isInFullScreen();
}
return false;
}
};
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
String videoUrl = null;
@ -138,16 +137,10 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
aspectRatio,
ResponseBodyUtils.getThumbUrl(media),
loadVideoOnItemClick,
// controlsBinding,
videoPlayerCallback);
// binding.itemFeedBottom.btnMute.setOnClickListener(v -> {
// final float newVol = videoPlayerViewHelper.toggleMute();
// setMuteIcon(newVol);
// Utils.sessionVolumeFull = newVol == 1f;
// });
binding.playerView.setOnClickListener(v -> {
if (sliderCallback != null) {
sliderCallback.onItemClicked(position);
sliderCallback.onItemClicked(position, media, binding.getRoot());
}
});
}
@ -161,62 +154,4 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
if (videoPlayerViewHelper == null) return;
videoPlayerViewHelper.releasePlayer();
}
// public void resetPlayerTimeline() {
// if (videoPlayerViewHelper == null) return;
// videoPlayerViewHelper.resetTimeline();
// }
//
// public void removeCallbacks() {
// if (videoPlayerViewHelper == null) return;
// videoPlayerViewHelper.removeCallbacks();
// }
// private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) {
// final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams();
// final int deviceWidth = Utils.displayMetrics.widthPixels;
// final int spanWidth = deviceWidth / spanCount;
// final int spanHeight = NumberUtils.getResultingHeight(spanWidth, feedModel.getImageHeight(), feedModel.getImageWidth());
// final int width = spanWidth == 0 ? deviceWidth : spanWidth;
// final int height = spanHeight == 0 ? deviceWidth + 1 : spanHeight;
// if (animate) {
// Animation animation = AnimationUtils.expand(
// binding.imageViewer,
// layoutParams.width,
// layoutParams.height,
// width,
// height,
// new Animation.AnimationListener() {
// @Override
// public void onAnimationStart(final Animation animation) {
// showOrHideDetails(spanCount);
// }
//
// @Override
// public void onAnimationEnd(final Animation animation) {
// // showOrHideDetails(spanCount);
// }
//
// @Override
// public void onAnimationRepeat(final Animation animation) {
//
// }
// });
// binding.imageViewer.startAnimation(animation);
// } else {
// layoutParams.width = width;
// layoutParams.height = height;
// binding.imageViewer.requestLayout();
// }
// }
//
// private void showOrHideDetails(final int spanCount) {
// if (spanCount == 1) {
// binding.itemFeedTop.getRoot().setVisibility(View.VISIBLE);
// binding.itemFeedBottom.getRoot().setVisibility(View.VISIBLE);
// } else {
// binding.itemFeedTop.getRoot().setVisibility(View.GONE);
// binding.itemFeedBottom.getRoot().setVisibility(View.GONE);
// }
// }
}

View File

@ -4,7 +4,6 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import androidx.recyclerview.widget.ItemTouchHelper;
import com.facebook.drawee.backends.pipeline.Fresco;
@ -23,6 +22,7 @@ import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemAnimatedMedia;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
import awais.instagrabber.utils.Utils;
@ -48,7 +48,7 @@ public class DirectItemAnimatedMediaViewHolder extends DirectItemViewHolder {
final AnimatedMediaFixedHeight fixedHeight = images.getFixedHeight();
if (fixedHeight == null) return;
final String url = fixedHeight.getWebp();
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
final NullSafePair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
fixedHeight.getHeight(),
fixedHeight.getWidth(),
mediaImageMaxHeight,
@ -56,8 +56,8 @@ public class DirectItemAnimatedMediaViewHolder extends DirectItemViewHolder {
);
binding.ivAnimatedMessage.setVisibility(View.VISIBLE);
final ViewGroup.LayoutParams layoutParams = binding.ivAnimatedMessage.getLayoutParams();
final int width = widthHeight.first != null ? widthHeight.first : 0;
final int height = widthHeight.second != null ? widthHeight.second : 0;
final int width = widthHeight.first;
final int height = widthHeight.second;
layoutParams.width = width;
layoutParams.height = height;
binding.ivAnimatedMessage.requestLayout();

View File

@ -6,7 +6,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.recyclerview.widget.ItemTouchHelper;
import com.facebook.drawee.drawable.ScalingUtils;
@ -31,6 +30,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemClip;
import awais.instagrabber.repositories.responses.directmessages.DirectItemFelixShare;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
import awais.instagrabber.utils.ResponseBodyUtils;
import awais.instagrabber.utils.Utils;
@ -103,15 +103,15 @@ public class DirectItemMediaShareViewHolder extends DirectItemViewHolder {
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
.setRoundingParams(roundingParams)
.build());
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
final NullSafePair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
media.getOriginalHeight(),
media.getOriginalWidth(),
mediaImageMaxHeight,
mediaImageMaxWidth
);
final ViewGroup.LayoutParams layoutParams = binding.mediaPreview.getLayoutParams();
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
layoutParams.width = widthHeight.first;
layoutParams.height = widthHeight.second;
binding.mediaPreview.requestLayout();
binding.mediaPreview.setTag(url);
binding.mediaPreview.setImageURI(url);

View File

@ -4,7 +4,6 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
@ -14,11 +13,11 @@ import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
import awais.instagrabber.databinding.LayoutDmBaseBinding;
import awais.instagrabber.databinding.LayoutDmMediaBinding;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.ImageVersions2;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
import awais.instagrabber.utils.ResponseBodyUtils;
@ -53,16 +52,16 @@ public class DirectItemMediaViewHolder extends DirectItemViewHolder {
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO || modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER
? View.VISIBLE
: View.GONE);
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
final NullSafePair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
media.getOriginalHeight(),
media.getOriginalWidth(),
mediaImageMaxHeight,
mediaImageMaxWidth
);
final ViewGroup.LayoutParams layoutParams = binding.mediaPreview.getLayoutParams();
final int width = widthHeight.first != null ? widthHeight.first : 0;
final int width = widthHeight.first;
layoutParams.width = width;
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
layoutParams.height = widthHeight.second;
binding.mediaPreview.requestLayout();
binding.bgTime.getLayoutParams().width = width;
binding.bgTime.requestLayout();

View File

@ -4,7 +4,6 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
@ -21,6 +20,7 @@ import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemVisualMedia;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
import awais.instagrabber.utils.ResponseBodyUtils;
import awais.instagrabber.utils.TextUtils;
@ -170,15 +170,15 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder {
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO || modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER
? View.VISIBLE
: View.GONE);
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
final NullSafePair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
media.getOriginalHeight(),
media.getOriginalWidth(),
mediaImageMaxHeight,
maxWidth
);
final ViewGroup.LayoutParams layoutParams = binding.preview.getLayoutParams();
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
layoutParams.width = widthHeight.first;
layoutParams.height = widthHeight.second;
binding.preview.requestLayout();
final String thumbUrl = ResponseBodyUtils.getThumbUrl(media);
binding.preview.setImageURI(thumbUrl);

View File

@ -5,7 +5,6 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import androidx.recyclerview.widget.ItemTouchHelper;
import com.facebook.drawee.drawable.ScalingUtils;
@ -17,12 +16,12 @@ import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
import awais.instagrabber.databinding.LayoutDmBaseBinding;
import awais.instagrabber.databinding.LayoutDmStoryShareBinding;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.ImageVersions2;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
import awais.instagrabber.utils.ResponseBodyUtils;
import awais.instagrabber.utils.TextUtils;
@ -76,15 +75,15 @@ public class DirectItemStoryShareViewHolder extends DirectItemViewHolder {
.setRoundingParams(roundingParams)
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
.build());
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
final NullSafePair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
storyShareMedia.getOriginalHeight(),
storyShareMedia.getOriginalWidth(),
mediaImageMaxHeight,
mediaImageMaxWidth
);
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
layoutParams.width = widthHeight.first;
layoutParams.height = widthHeight.second;
binding.ivMediaPreview.requestLayout();
final String thumbUrl = ResponseBodyUtils.getThumbUrl(storyShareMedia);
binding.ivMediaPreview.setImageURI(thumbUrl);

View File

@ -551,6 +551,10 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder imple
menu.setOnDismissListener(() -> setSelected(false));
menu.setOnReactionClickListener(emoji -> callback.onReaction(item, emoji));
menu.setOnOptionSelectListener((itemId, cb) -> callback.onOptionSelect(item, itemId, cb));
menu.setOnAddReactionListener(() -> {
menu.dismiss();
itemView.postDelayed(() -> callback.onAddReactionListener(item), 300);
});
menu.show(itemView, location);
}

View File

@ -4,7 +4,6 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import androidx.recyclerview.widget.ItemTouchHelper;
import com.facebook.drawee.backends.pipeline.Fresco;
@ -16,6 +15,7 @@ import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemXma;
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
import awais.instagrabber.utils.NullSafePair;
import awais.instagrabber.utils.NumberUtils;
public class DirectItemXmaViewHolder extends DirectItemViewHolder {
@ -43,7 +43,7 @@ public class DirectItemXmaViewHolder extends DirectItemViewHolder {
}
final DirectItemXma.XmaUrlInfo urlInfo = playableUrlInfo != null ? playableUrlInfo : previewUrlInfo;
final String url = urlInfo.getUrl();
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
final NullSafePair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
urlInfo.getHeight(),
urlInfo.getWidth(),
mediaImageMaxHeight,
@ -51,8 +51,8 @@ public class DirectItemXmaViewHolder extends DirectItemViewHolder {
);
binding.ivAnimatedMessage.setVisibility(View.VISIBLE);
final ViewGroup.LayoutParams layoutParams = binding.ivAnimatedMessage.getLayoutParams();
final int width = widthHeight.first != null ? widthHeight.first : 0;
final int height = widthHeight.second != null ? widthHeight.second : 0;
final int width = widthHeight.first;
final int height = widthHeight.second;
layoutParams.width = width;
layoutParams.height = height;
binding.ivAnimatedMessage.requestLayout();

View File

@ -45,9 +45,9 @@ public class FeedSliderViewHolder extends FeedItemViewHolder {
final String text = "1/" + sliderItemLen;
binding.mediaCounter.setText(text);
binding.mediaList.setOffscreenPageLimit(1);
final SliderItemsAdapter adapter = new SliderItemsAdapter(null, false, new SliderCallbackAdapter() {
final SliderItemsAdapter adapter = new SliderItemsAdapter(false, new SliderCallbackAdapter() {
@Override
public void onItemClicked(final int position) {
public void onItemClicked(final int position, final Media media, final View view) {
feedItemCallback.onSliderClick(feedModel, position);
}
});

View File

@ -105,12 +105,15 @@ public class ChatMessageLayout extends FrameLayout {
viewPartMainLastLineWidth = viewPartMainLineCount > 0
? ((TextView) firstChild).getLayout().getLineWidth(viewPartMainLineCount - 1)
: 0;
// also include start left padding
viewPartMainLastLineWidth += firstChild.getPaddingLeft();
}
if (viewPartMainLineCount > 1 && !(viewPartMainLastLineWidth + viewPartInfoWidth > viewPartMain.getMeasuredWidth())) {
final float lastLineWithInfoWidth = viewPartMainLastLineWidth + viewPartInfoWidth;
if (viewPartMainLineCount > 1 && lastLineWithInfoWidth <= viewPartMain.getMeasuredWidth()) {
widthSize += viewPartMainWidth;
heightSize += viewPartMainHeight;
} else if (viewPartMainLineCount > 1 && (viewPartMainLastLineWidth + viewPartInfoWidth > availableWidth)) {
} else if (viewPartMainLineCount > 1 && (lastLineWithInfoWidth > availableWidth)) {
widthSize += viewPartMainWidth;
heightSize += viewPartMainHeight + viewPartInfoHeight;
} else if (viewPartMainLineCount == 1 && (viewPartMainWidth + viewPartInfoWidth > availableWidth)) {
@ -120,6 +123,16 @@ public class ChatMessageLayout extends FrameLayout {
heightSize += viewPartMainHeight;
widthSize += viewPartMainWidth + viewPartInfoWidth;
}
// if (isInEditMode()) {
// TextView wDebugView = (TextView) ((ViewGroup) this.getParent()).findViewWithTag("debug");
// wDebugView.setText(lastLineWithInfoWidth
// + "\n" + availableWidth
// + "\n" + viewPartMain.getMeasuredWidth()
// + "\n" + (lastLineWithInfoWidth <= viewPartMain.getMeasuredWidth())
// + "\n" + (lastLineWithInfoWidth > availableWidth)
// + "\n" + (viewPartMainWidth + viewPartInfoWidth > availableWidth));
// }
}
setMeasuredDimension(widthSize, heightSize);
super.onMeasure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY));

View File

@ -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);
}
});
}
}

View File

@ -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();
}
}

View File

@ -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()));
}
}

View File

@ -3,6 +3,8 @@ package awais.instagrabber.customviews;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -25,6 +27,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import awais.instagrabber.adapters.FeedAdapterV2;
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration;
@ -60,14 +63,17 @@ public class PostsRecyclerView extends RecyclerView {
private FeedAdapterV2.FeedItemCallback feedItemCallback;
private boolean shouldScrollToTop;
private FeedAdapterV2.SelectionModeCallback selectionModeCallback;
private Function<ViewGroup, View> headerViewCreator;
private Function<View, Void> headerBinder;
private boolean refresh = true;
private final List<FetchStatusChangeListener> fetchStatusChangeListeners = new ArrayList<>();
private final FetchListener<List<Media>> fetchListener = new FetchListener<List<Media>>() {
@Override
public void onResult(final List<Media> result) {
final int currentPage = lazyLoader.getCurrentPage();
if (currentPage == 0) {
if (refresh) {
refresh = false;
mediaViewModel.getList().postValue(result);
shouldScrollToTop = true;
dispatchFetchStatus();
@ -198,21 +204,19 @@ public class PostsRecyclerView extends RecyclerView {
Log.e(TAG, "initSelf: ", e);
}
if (mediaViewModel == null) return;
mediaViewModel.getList().observe(lifeCycleOwner, list -> {
if (list.size() <= 0) return;
feedAdapter.submitList(list, () -> {
// postDelayed(this::fetchMoreIfPossible, 1000);
if (!shouldScrollToTop) return;
smoothScrollToPosition(0);
shouldScrollToTop = false;
});
});
mediaViewModel.getList().observe(lifeCycleOwner, list -> feedAdapter.submitList(list, () -> {
// postDelayed(this::fetchMoreIfPossible, 1000);
if (!shouldScrollToTop) return;
shouldScrollToTop = false;
post(() -> smoothScrollToPosition(0));
}));
postFetcher = new PostFetcher(postFetchService, fetchListener);
if (layoutPreferences.getHasGap()) {
addItemDecoration(gridSpacingItemDecoration);
}
setHasFixedSize(true);
setNestedScrollingEnabled(true);
setItemAnimator(null);
lazyLoader = new RecyclerLazyLoaderAtEdge(layoutManager, (page) -> {
if (postFetcher.hasMore()) {
postFetcher.fetch();
@ -316,11 +320,12 @@ public class PostsRecyclerView extends RecyclerView {
}
public void refresh() {
refresh = true;
if (lazyLoader != null) {
lazyLoader.resetState();
}
if (postFetcher != null) {
mediaViewModel.getList().postValue(Collections.emptyList());
// mediaViewModel.getList().postValue(Collections.emptyList());
postFetcher.reset();
postFetcher.fetch();
}

View File

@ -9,20 +9,20 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatTextView;
import awais.instagrabber.utils.AppExecutors;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.utils.ViewUtils;
public class Tooltip extends AppCompatTextView {
private View anchor;
private ViewPropertyAnimator animator;
private boolean showing;
private final AppExecutors appExecutors;
private final AppExecutors appExecutors = AppExecutors.getInstance();
private final Runnable dismissRunnable = () -> {
animator = animate().alpha(0).setListener(new AnimatorListenerAdapter() {
@Override
@ -33,7 +33,7 @@ public class Tooltip extends AppCompatTextView {
animator.start();
};
public Tooltip(Context context, ViewGroup parentView, int backgroundColor, int textColor) {
public Tooltip(@NonNull Context context, @NonNull ViewGroup parentView, int backgroundColor, int textColor) {
super(context);
setBackgroundDrawable(ViewUtils.createRoundRectDrawable(Utils.convertDpToPx(3), backgroundColor));
setTextColor(textColor);
@ -43,7 +43,6 @@ public class Tooltip extends AppCompatTextView {
parentView.addView(this, ViewUtils.createFrame(
ViewUtils.WRAP_CONTENT, ViewUtils.WRAP_CONTENT, Gravity.START | Gravity.TOP, 5, 0, 5, 3));
setVisibility(GONE);
appExecutors = AppExecutors.getInstance();
}
@Override

View File

@ -1,5 +1,7 @@
package awais.instagrabber.customviews;
import com.google.android.exoplayer2.ui.StyledPlayerView;
public class VideoPlayerCallbackAdapter implements VideoPlayerViewHelper.VideoPlayerCallback {
@Override
public void onThumbnailLoaded() {}
@ -18,4 +20,12 @@ public class VideoPlayerCallbackAdapter implements VideoPlayerViewHelper.VideoPl
@Override
public void onRelease() {}
@Override
public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) {}
@Override
public boolean isInFullScreen() {
return false;
}
}

View File

@ -1,14 +1,19 @@
package awais.instagrabber.customviews;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.drawable.Animatable;
import android.net.Uri;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageButton;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
@ -22,16 +27,23 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioListener;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.StyledPlayerControlView;
import com.google.android.exoplayer2.ui.StyledPlayerView;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.material.button.MaterialButton;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import awais.instagrabber.R;
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
import awais.instagrabber.utils.Utils;
public class VideoPlayerViewHelper implements Player.EventListener {
private static final String TAG = "VideoPlayerViewHelper";
// private static final long INITIAL_DELAY = 0;
// private static final long RECURRING_DELAY = 60;
private static final String TAG = VideoPlayerViewHelper.class.getSimpleName();
private final Context context;
private final LayoutVideoPlayerWithThumbnailBinding binding;
@ -39,74 +51,20 @@ public class VideoPlayerViewHelper implements Player.EventListener {
private final float thumbnailAspectRatio;
private final String thumbnailUrl;
private final boolean loadPlayerOnClick;
// private final LayoutExoCustomControlsBinding controlsBinding;
private final VideoPlayerCallback videoPlayerCallback;
private final String videoUrl;
private final DefaultDataSourceFactory dataSourceFactory;
private SimpleExoPlayer player;
private PopupMenu speedPopup;
// private PositionCheckRunnable positionChecker;
// private Handler positionUpdateHandler;
private AppCompatImageButton mute;
// private final Player.EventListener listener = new Player.EventListener() {
// @Override
// public void onPlaybackStateChanged(final int state) {
// // switch (state) {
// // case Player.STATE_BUFFERING:
// // case STATE_IDLE:
// // case STATE_ENDED:
// // positionUpdateHandler.removeCallbacks(positionChecker);
// // return;
// // case STATE_READY:
// // setupTimeline();
// // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY);
// // break;
// // }
// }
//
// @Override
// public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) {
// // updatePlayPauseDrawable(playWhenReady);
// // if (positionUpdateHandler == null || positionChecker == null) return;
// // if (playWhenReady) {
// // positionUpdateHandler.removeCallbacks(positionChecker);
// // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY);
// // }
// }
// };
private final AudioListener audioListener = new AudioListener() {
@Override
public void onVolumeChanged(final float volume) {
updateMuteIcon(volume);
}
};
// private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> {
// if (!fromUser) return;
// long actualValue = (long) value;
// if (actualValue < 0) {
// actualValue = 0;
// } else if (actualValue > player.getDuration()) {
// actualValue = player.getDuration();
// }
// player.seekTo(actualValue);
// };
// private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady());
// // private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value);
private final View.OnClickListener muteOnClickListener = v -> toggleMute();
private MaterialButton mute;
// private final View.OnClickListener rewOnClickListener = v -> {
// final long positionMs = player.getCurrentPosition() - 5000;
// player.seekTo(positionMs < 0 ? 0 : positionMs);
// };
// private final View.OnClickListener ffOnClickListener = v -> {
// long positionMs = player.getCurrentPosition() + 5000;
// long duration = player.getDuration();
// if (duration == TIME_UNSET) {
// duration = 0;
// }
// player.seekTo(Math.min(positionMs, duration));
// };
// private final View.OnClickListener showMenu = this::showMenu;
private Object layoutManager;
public VideoPlayerViewHelper(@NonNull final Context context,
@NonNull final LayoutVideoPlayerWithThumbnailBinding binding,
@ -115,7 +73,6 @@ public class VideoPlayerViewHelper implements Player.EventListener {
final float thumbnailAspectRatio,
final String thumbnailUrl,
final boolean loadPlayerOnClick,
// final LayoutExoCustomControlsBinding controlsBinding,
final VideoPlayerCallback videoPlayerCallback) {
this.context = context;
this.binding = binding;
@ -123,7 +80,6 @@ public class VideoPlayerViewHelper implements Player.EventListener {
this.thumbnailAspectRatio = thumbnailAspectRatio;
this.thumbnailUrl = thumbnailUrl;
this.loadPlayerOnClick = loadPlayerOnClick;
// this.controlsBinding = controlsBinding;
this.videoPlayerCallback = videoPlayerCallback;
this.videoUrl = videoUrl;
this.dataSourceFactory = new DefaultDataSourceFactory(binding.getRoot().getContext(), "instagram");
@ -140,7 +96,6 @@ public class VideoPlayerViewHelper implements Player.EventListener {
}
});
setThumbnail();
// setupControls();
}
private void setThumbnail() {
@ -149,25 +104,25 @@ public class VideoPlayerViewHelper implements Player.EventListener {
if (thumbnailUrl != null) {
thumbnailRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(thumbnailUrl)).build();
}
final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder()
.setControllerListener(new BaseControllerListener<ImageInfo>() {
@Override
public void onFailure(final String id,
final Throwable throwable) {
if (videoPlayerCallback != null) {
videoPlayerCallback.onThumbnailLoaded();
}
}
final PipelineDraweeControllerBuilder builder = Fresco
.newDraweeControllerBuilder()
.setControllerListener(new BaseControllerListener<ImageInfo>() {
@Override
public void onFailure(final String id, final Throwable throwable) {
if (videoPlayerCallback != null) {
videoPlayerCallback.onThumbnailLoaded();
}
}
@Override
public void onFinalImageSet(final String id,
final ImageInfo imageInfo,
final Animatable animatable) {
if (videoPlayerCallback != null) {
videoPlayerCallback.onThumbnailLoaded();
}
}
});
@Override
public void onFinalImageSet(final String id,
final ImageInfo imageInfo,
final Animatable animatable) {
if (videoPlayerCallback != null) {
videoPlayerCallback.onThumbnailLoaded();
}
}
});
if (thumbnailRequest != null) {
builder.setImageRequest(thumbnailRequest);
}
@ -176,8 +131,8 @@ public class VideoPlayerViewHelper implements Player.EventListener {
private void loadPlayer() {
if (videoUrl == null) return;
if (binding.root.getDisplayedChild() == 0) {
binding.root.showNext();
if (binding.getRoot().getDisplayedChild() == 0) {
binding.getRoot().showNext();
}
if (videoPlayerCallback != null) {
videoPlayerCallback.onPlayerViewLoaded();
@ -186,14 +141,13 @@ public class VideoPlayerViewHelper implements Player.EventListener {
if (player != null) {
player.release();
}
final ViewGroup.LayoutParams playerViewLayoutParams = binding.playerView.getLayoutParams();
if (playerViewLayoutParams.height > Utils.displayMetrics.heightPixels * 0.8) {
playerViewLayoutParams.height = (int) (Utils.displayMetrics.heightPixels * 0.8);
}
player = new SimpleExoPlayer.Builder(context)
.setLooper(Looper.getMainLooper())
.build();
// positionUpdateHandler = new Handler();
// positionChecker = new PositionCheckRunnable(positionUpdateHandler,
// player,
// controlsBinding.timeline,
// controlsBinding.fromTime);
player.addListener(this);
player.addAudioListener(audioListener);
player.setVolume(initialVolume);
@ -203,135 +157,118 @@ public class VideoPlayerViewHelper implements Player.EventListener {
final MediaItem mediaItem = MediaItem.fromUri(videoUrl);
final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem);
player.setMediaSource(mediaSource);
// setupControls();
player.prepare();
binding.playerView.setPlayer(player);
binding.playerView.setShowFastForwardButton(false);
binding.playerView.setShowRewindButton(false);
// binding.controls.setPlayer(player);
mute = binding.playerView.findViewById(R.id.mute);
// mute = binding.controls.findViewById(R.id.mute);
if (mute != null) {
mute.setOnClickListener(muteOnClickListener);
}
updateMuteIcon(player.getVolume());
binding.playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
binding.playerView.setShowNextButton(false);
binding.playerView.setShowPreviousButton(false);
binding.playerView.setControllerOnFullScreenModeChangedListener(isFullScreen -> {
if (videoPlayerCallback == null) return;
videoPlayerCallback.onFullScreenModeChanged(isFullScreen, binding.playerView);
});
setupControllerView();
}
// private void setupControls() {
// if (controlsBinding == null) return;
// // binding.playerView.setUseController(false);
// if (player == null) {
// // enableControls(false);
// // controlsBinding.playPause.setEnabled(true);
// // controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent));
// return;
// }
// // enableControls(true);
// // updatePlayPauseDrawable(player.getPlayWhenReady());
// // updateMuteIcon(player.getVolume());
// player.addListener(listener);
// // player.addAudioListener(audioListener);
// // controlsBinding.timeline.addOnChangeListener(onChangeListener);
// // controlsBinding.timeline.setLabelFormatter(labelFormatter);
// // controlsBinding.playPause.setOnClickListener(onClickListener);
// // controlsBinding.mute.setOnClickListener(muteOnClickListener);
// // controlsBinding.rewWithAmount.setOnClickListener(rewOnClickListener);
// // controlsBinding.ffWithAmount.setOnClickListener(ffOnClickListener);
// // controlsBinding.speed.setOnClickListener(showMenu);
// }
private void setupControllerView() {
try {
final StyledPlayerControlView controllerView = getStyledPlayerControlView();
if (controllerView == null) return;
layoutManager = setControlViewLayoutManager(controllerView);
if (videoPlayerCallback != null && videoPlayerCallback.isInFullScreen()) {
setControllerViewToFullScreenMode(controllerView);
}
final ViewGroup exoBasicControls = controllerView.findViewById(R.id.exo_basic_controls);
if (exoBasicControls == null) return;
mute = new AppCompatImageButton(context);
final Resources resources = context.getResources();
if (resources == null) return;
final int width = resources.getDimensionPixelSize(R.dimen.exo_small_icon_width);
final int height = resources.getDimensionPixelSize(R.dimen.exo_small_icon_height);
final int margin = resources.getDimensionPixelSize(R.dimen.exo_small_icon_horizontal_margin);
final int paddingHorizontal = resources.getDimensionPixelSize(R.dimen.exo_small_icon_padding_horizontal);
final int paddingVertical = resources.getDimensionPixelSize(R.dimen.exo_small_icon_padding_vertical);
final ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(width, height);
layoutParams.setMargins(margin, 0, margin, 0);
mute.setLayoutParams(layoutParams);
mute.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical);
mute.setScaleType(ImageView.ScaleType.FIT_XY);
mute.setBackgroundResource(Utils.getAttrResId(context, android.R.attr.selectableItemBackground));
mute.setImageTintList(ColorStateList.valueOf(resources.getColor(R.color.white)));
updateMuteIcon(player.getVolume());
exoBasicControls.addView(mute, 0);
mute.setOnClickListener(muteOnClickListener);
} catch (Exception e) {
Log.e(TAG, "loadPlayer: ", e);
}
}
// private void setupTimeline() {
// final long duration = player.getDuration();
// controlsBinding.timeline.setEnabled(true);
// controlsBinding.timeline.setValueFrom(0);
// controlsBinding.timeline.setValueTo(duration);
// controlsBinding.fromTime.setText(TextUtils.millisToTimeString(0));
// controlsBinding.toTime.setText(TextUtils.millisToTimeString(duration));
// }
@Nullable
private Object setControlViewLayoutManager(@NonNull final StyledPlayerControlView controllerView)
throws NoSuchFieldException, IllegalAccessException {
final Field controlViewLayoutManagerField = controllerView.getClass().getDeclaredField("controlViewLayoutManager");
controlViewLayoutManagerField.setAccessible(true);
return controlViewLayoutManagerField.get(controllerView);
}
// private void enableControls(final boolean enable) {
// controlsBinding.speed.setEnabled(enable);
// controlsBinding.speed.setClickable(enable);
// controlsBinding.mute.setEnabled(enable);
// controlsBinding.mute.setClickable(enable);
// controlsBinding.ffWithAmount.setEnabled(enable);
// controlsBinding.ffWithAmount.setClickable(enable);
// controlsBinding.rewWithAmount.setEnabled(enable);
// controlsBinding.rewWithAmount.setClickable(enable);
// // controlsBinding.fromTime.setEnabled(enable);
// // controlsBinding.toTime.setEnabled(enable);
// controlsBinding.playPause.setEnabled(enable);
// controlsBinding.playPause.setClickable(enable);
// // controlsBinding.timeline.setEnabled(enable);
// }
private void setControllerViewToFullScreenMode(@NonNull final StyledPlayerControlView controllerView)
throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// Exoplayer doesn't expose the fullscreen state, so using reflection
final Field fullScreenButtonField = controllerView.getClass().getDeclaredField("fullScreenButton");
fullScreenButtonField.setAccessible(true);
final ImageView fullScreenButton = (ImageView) fullScreenButtonField.get(controllerView);
final Field isFullScreen = controllerView.getClass().getDeclaredField("isFullScreen");
isFullScreen.setAccessible(true);
isFullScreen.set(controllerView, true);
final Method updateFullScreenButtonForState = controllerView
.getClass()
.getDeclaredMethod("updateFullScreenButtonForState", ImageView.class, boolean.class);
updateFullScreenButtonForState.setAccessible(true);
updateFullScreenButtonForState.invoke(controllerView, fullScreenButton, true);
// public void showMenu(View anchor) {
// PopupMenu popup = getPopupMenu(anchor);
// popup.show();
// }
}
// @NonNull
// private PopupMenu getPopupMenu(final View anchor) {
// if (speedPopup != null) {
// return speedPopup;
// }
// final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle);
// // final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_PopupMenu_Exoplayer);
// speedPopup = new PopupMenu(themeWrapper, anchor);
// speedPopup.getMenuInflater().inflate(R.menu.speed_menu, speedPopup.getMenu());
// speedPopup.setOnMenuItemClickListener(item -> {
// float nextSpeed;
// int textResId;
// int itemId = item.getItemId();
// if (itemId == R.id.pt_two_five_x) {
// nextSpeed = 0.25f;
// textResId = R.string.pt_two_five_x;
// } else if (itemId == R.id.pt_five_x) {
// nextSpeed = 0.5f;
// textResId = R.string.pt_five_x;
// } else if (itemId == R.id.pt_seven_five_x) {
// nextSpeed = 0.75f;
// textResId = R.string.pt_seven_five_x;
// } else if (itemId == R.id.one_x) {
// nextSpeed = 1f;
// textResId = R.string.one_x;
// } else if (itemId == R.id.one_pt_two_five_x) {
// nextSpeed = 1.25f;
// textResId = R.string.one_pt_two_five_x;
// } else if (itemId == R.id.one_pt_five_x) {
// nextSpeed = 1.5f;
// textResId = R.string.one_pt_five_x;
// } else if (itemId == R.id.two_x) {
// nextSpeed = 2f;
// textResId = R.string.two_x;
// } else {
// nextSpeed = 1;
// textResId = R.string.one_x;
// }
// player.setPlaybackParameters(new PlaybackParameters(nextSpeed));
// controlsBinding.speed.setText(textResId);
// return true;
// });
// return speedPopup;
// }
@Nullable
private StyledPlayerControlView getStyledPlayerControlView() throws NoSuchFieldException, IllegalAccessException {
final Field controller = binding.playerView.getClass().getDeclaredField("controller");
controller.setAccessible(true);
return (StyledPlayerControlView) controller.get(binding.playerView);
}
@Override
public void onTracksChanged(@NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) {
if (trackGroups.isEmpty()) {
setHasAudio(false);
return;
}
boolean hasAudio = false;
for (int i = 0; i < trackGroups.length; i++) {
for (int g = 0; g < trackGroups.get(i).length; g++) {
final String sampleMimeType = trackGroups.get(i).getFormat(g).sampleMimeType;
if (sampleMimeType != null && sampleMimeType.contains("audio")) {
hasAudio = true;
break;
}
}
}
setHasAudio(hasAudio);
}
private void setHasAudio(final boolean hasAudio) {
if (mute == null) return;
mute.setEnabled(hasAudio);
mute.setAlpha(hasAudio ? 1f : 0.5f);
updateMuteIcon(hasAudio ? 1f : 0f);
}
private void updateMuteIcon(final float volume) {
if (mute == null) return;
if (volume == 0) {
mute.setIconResource(R.drawable.ic_volume_off_24_states);
mute.setImageResource(R.drawable.ic_volume_off_24);
return;
}
mute.setIconResource(R.drawable.ic_volume_up_24_states);
mute.setImageResource(R.drawable.ic_volume_up_24);
}
// private void updatePlayPauseDrawable(final boolean playWhenReady) {
// if (playWhenReady) {
// controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24);
// return;
// }
// controlsBinding.playPause.setIconResource(R.drawable.ic_play_states);
// }
@Override
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) {
if (videoPlayerCallback == null) return;
@ -349,18 +286,18 @@ public class VideoPlayerViewHelper implements Player.EventListener {
private void toggleMute() {
if (player == null) return;
if (layoutManager != null) {
try {
final Method resetHideCallbacks = layoutManager.getClass().getDeclaredMethod("resetHideCallbacks");
resetHideCallbacks.invoke(layoutManager);
} catch (Exception e) {
Log.e(TAG, "toggleMute: ", e);
}
}
final float vol = player.getVolume() == 0f ? 1f : 0f;
player.setVolume(vol);
}
// public void togglePlayback() {
// if (player == null) return;
// final int playbackState = player.getPlaybackState();
// if (playbackState == STATE_IDLE || playbackState == STATE_ENDED) return;
// final boolean playWhenReady = player.getPlayWhenReady();
// player.setPlayWhenReady(!playWhenReady);
// }
public void releasePlayer() {
if (videoPlayerCallback != null) {
videoPlayerCallback.onRelease();
@ -369,86 +306,14 @@ public class VideoPlayerViewHelper implements Player.EventListener {
player.release();
player = null;
}
// if (positionUpdateHandler != null) {
// if (positionChecker != null) {
// positionUpdateHandler.removeCallbacks(positionChecker);
// positionChecker = null;
// }
// positionUpdateHandler = null;
// }
}
public void pause() {
if (player != null) {
player.pause();
}
// if (positionUpdateHandler != null) {
// if (positionChecker != null) {
// positionUpdateHandler.removeCallbacks(positionChecker);
// }
// }
}
// public void resetTimeline() {
// if (player == null) {
// enableControls(false);
// return;
// }
// setupTimeline();
// final long currentPosition = player.getCurrentPosition();
// controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration()));
// setupControls();
// }
// public void removeCallbacks() {
// if (player != null) {
// player.removeListener(listener);
// player.removeAudioListener(audioListener);
// }
// controlsBinding.timeline.removeOnChangeListener(onChangeListener);
// controlsBinding.timeline.setLabelFormatter(null);
// controlsBinding.playPause.setOnClickListener(null);
// controlsBinding.mute.setOnClickListener(null);
// controlsBinding.rewWithAmount.setOnClickListener(null);
// controlsBinding.ffWithAmount.setOnClickListener(null);
// controlsBinding.speed.setOnClickListener(null);
// }
// private static class PositionCheckRunnable implements Runnable {
// private final Handler positionUpdateHandler;
// private final SimpleExoPlayer player;
// private final Slider timeline;
// private final AppCompatTextView fromTime;
//
// public PositionCheckRunnable(final Handler positionUpdateHandler,
// final SimpleExoPlayer simpleExoPlayer,
// final Slider slider,
// final AppCompatTextView fromTime) {
// this.positionUpdateHandler = positionUpdateHandler;
// this.player = simpleExoPlayer;
// this.timeline = slider;
// this.fromTime = fromTime;
// }
//
// @Override
// public void run() {
// if (positionUpdateHandler == null) return;
// positionUpdateHandler.removeCallbacks(this);
// if (player == null) return;
// final long currentPosition = player.getCurrentPosition();
// final long duration = player.getDuration();
// if (duration == TIME_UNSET) {
// timeline.setValueFrom(0);
// timeline.setValueTo(0);
// timeline.setEnabled(false);
// return;
// }
// timeline.setValue(Math.min(currentPosition, duration));
// fromTime.setText(TextUtils.millisToTimeString(currentPosition));
// positionUpdateHandler.postDelayed(this, RECURRING_DELAY);
// }
// }
public interface VideoPlayerCallback {
void onThumbnailLoaded();
@ -461,5 +326,9 @@ public class VideoPlayerViewHelper implements Player.EventListener {
void onPause();
void onRelease();
void onFullScreenModeChanged(boolean isFullScreen, final StyledPlayerView playerView);
boolean isInFullScreen();
}
}

View File

@ -228,7 +228,7 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
public void setZoomingEnabled(boolean zoomingEnabled) {
mZoomingEnabled = zoomingEnabled;
mZoomableController.setEnabled(false);
mZoomableController.setEnabled(zoomingEnabled);
}
/**

View File

@ -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);
}
}

View File

@ -43,7 +43,7 @@ public class EmojiGridAdapter extends RecyclerView.Adapter<EmojiGridAdapter.Emoj
private final EmojiVariantManager emojiVariantManager;
private final AppExecutors appExecutors;
public EmojiGridAdapter(@NonNull final EmojiCategoryType emojiCategoryType,
public EmojiGridAdapter(final EmojiCategoryType emojiCategoryType,
final OnEmojiClickListener onEmojiClickListener,
final OnEmojiLongClickListener onEmojiLongClickListener) {
this.onEmojiClickListener = onEmojiClickListener;
@ -55,6 +55,11 @@ public class EmojiGridAdapter extends RecyclerView.Adapter<EmojiGridAdapter.Emoj
emojiVariantManager = EmojiVariantManager.getInstance();
appExecutors = AppExecutors.getInstance();
setHasStableIds(true);
if (emojiCategoryType == null) {
// show all if type is null
differ.submitList(ImmutableList.copyOf(emojiParser.getAllEmojis().values()));
return;
}
final EmojiCategory emojiCategory = categoryMap.get(emojiCategoryType);
if (emojiCategory == null) {
differ.submitList(Collections.emptyList());
@ -105,7 +110,7 @@ public class EmojiGridAdapter extends RecyclerView.Adapter<EmojiGridAdapter.Emoj
}
public static class EmojiViewHolder extends RecyclerView.ViewHolder {
private final AppExecutors appExecutors = AppExecutors.getInstance();
// private final AppExecutors appExecutors = AppExecutors.getInstance();
private final ItemEmojiGridBinding binding;
private final OnEmojiClickListener onEmojiClickListener;
private final OnEmojiLongClickListener onEmojiLongClickListener;
@ -123,17 +128,17 @@ public class EmojiGridAdapter extends RecyclerView.Adapter<EmojiGridAdapter.Emoj
binding.image.setImageDrawable(null);
binding.indicator.setVisibility(View.GONE);
itemView.setOnLongClickListener(null);
itemView.post(() -> {
binding.image.setImageDrawable(emoji.getDrawable());
final boolean hasVariants = !parent.getVariants().isEmpty();
binding.indicator.setVisibility(hasVariants ? View.VISIBLE : View.GONE);
if (onEmojiClickListener != null) {
itemView.setOnClickListener(v -> onEmojiClickListener.onClick(v, emoji));
}
if (hasVariants && onEmojiLongClickListener != null) {
itemView.setOnLongClickListener(v -> onEmojiLongClickListener.onLongClick(position, v, parent));
}
});
// itemView.post(() -> {
binding.image.setImageDrawable(emoji.getDrawable());
final boolean hasVariants = !parent.getVariants().isEmpty();
binding.indicator.setVisibility(hasVariants ? View.VISIBLE : View.GONE);
if (onEmojiClickListener != null) {
itemView.setOnClickListener(v -> onEmojiClickListener.onClick(v, emoji));
}
if (hasVariants && onEmojiLongClickListener != null) {
itemView.setOnLongClickListener(v -> onEmojiLongClickListener.onLongClick(position, v, parent));
}
// });
}
}

View File

@ -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();
}
}

View File

@ -25,7 +25,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Spanned;
import android.text.TextPaint;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.emoji.text.EmojiCompat;

View File

@ -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);
}
}
}

View File

@ -1,5 +1,7 @@
package awais.instagrabber.customviews.helpers;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
@ -12,6 +14,13 @@ import com.google.android.material.bottomnavigation.BottomNavigationView;
public class CustomHideBottomViewOnScrollBehavior extends HideBottomViewOnScrollBehavior<BottomNavigationView> {
private static final String TAG = "CustomHideBottomView";
public CustomHideBottomViewOnScrollBehavior() {
}
public CustomHideBottomViewOnScrollBehavior(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(@NonNull final CoordinatorLayout coordinatorLayout,
@NonNull final BottomNavigationView child,
@ -23,7 +32,13 @@ public class CustomHideBottomViewOnScrollBehavior extends HideBottomViewOnScroll
}
@Override
public void onNestedPreScroll(@NonNull final CoordinatorLayout coordinatorLayout, @NonNull final BottomNavigationView child, @NonNull final View target, final int dx, final int dy, @NonNull final int[] consumed, final int type) {
public void onNestedPreScroll(@NonNull final CoordinatorLayout coordinatorLayout,
@NonNull final BottomNavigationView child,
@NonNull final View target,
final int dx,
final int dy,
@NonNull final int[] consumed,
final int type) {
if (dy > 0) {
slideDown(child);
} else if (dy < 0) {

View File

@ -7,17 +7,24 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int spacing;
private final int halfSpace;
private boolean hasHeader;
public GridSpacingItemDecoration(int spacing) {
this.spacing = spacing;
halfSpace = spacing / 2;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
final int halfSpace = spacing / 2;
if (hasHeader && parent.getChildAdapterPosition(view) == 0) {
outRect.bottom = halfSpace;
outRect.left = -halfSpace;
outRect.right = -halfSpace;
return;
}
if (parent.getPaddingLeft() != halfSpace) {
parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace);
parent.setPadding(halfSpace, hasHeader ? 0 : halfSpace, halfSpace, halfSpace);
parent.setClipToPadding(false);
}
outRect.top = halfSpace;
@ -25,4 +32,8 @@ public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
outRect.left = halfSpace;
outRect.right = halfSpace;
}
public void setHasHeader(final boolean hasHeader) {
this.hasHeader = hasHeader;
}
}

View File

@ -134,7 +134,14 @@ public class ProfilePicDialogFragment extends DialogFragment {
@Override
public void onSuccess(final User result) {
if (result != null) {
setupPhoto(result.getHDProfilePicUrl());
final String url = result.getHDProfilePicUrl();
if (url == null) {
final Context context = getContext();
if (context == null) return;
Toast.makeText(context, R.string.no_profile_pic_found, Toast.LENGTH_LONG).show();
return;
}
setupPhoto(url);
}
}

View File

@ -190,16 +190,15 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay
final View profilePicView,
final View mainPostImage,
final int position) {
final PostViewV2Fragment.Builder builder = PostViewV2Fragment
.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
final NavController navController = NavHostFragment.findNavController(CollectionPostsFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
builder.build().show(getChildFragmentManager(), "post_view");
}
};
private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {
@ -243,8 +242,10 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay
super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity();
final TransitionSet transitionSet = new TransitionSet();
final Context context = getContext();
if (context == null) return;
transitionSet.addTransition(new ChangeBounds())
.addTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move))
.addTransition(TransitionInflater.from(context).inflateTransition(android.R.transition.move))
.setDuration(200);
setSharedElementEnterTransition(transitionSet);
postponeEnterTransition();
@ -280,7 +281,8 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay
@Override
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
inflater.inflate(R.menu.collection_posts_menu, menu);
// delaying to make toolbar resume animation smooth, otherwise lags
binding.getRoot().postDelayed(() -> inflater.inflate(R.menu.collection_posts_menu, menu), 500);
}
@Override
@ -288,62 +290,60 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay
if (item.getItemId() == R.id.layout) {
showPostsLayoutPreferences();
return true;
}
else if (item.getItemId() == R.id.delete) {
} else if (item.getItemId() == R.id.delete) {
final Context context = getContext();
if (context == null) return false;
new AlertDialog.Builder(context)
.setTitle(R.string.delete_collection)
.setMessage(R.string.delete_collection_note)
.setPositiveButton(R.string.confirm, (d, w) -> {
collectionService.deleteCollection(
savedCollection.getId(),
new ServiceCallback<String>() {
@Override
public void onSuccess(final String result) {
SavedCollectionsFragment.pleaseRefresh = true;
NavHostFragment.findNavController(CollectionPostsFragment.this).navigateUp();
}
.setPositiveButton(R.string.confirm, (d, w) -> collectionService.deleteCollection(
savedCollection.getId(),
new ServiceCallback<String>() {
@Override
public void onSuccess(final String result) {
SavedCollectionsFragment.pleaseRefresh = true;
NavHostFragment.findNavController(CollectionPostsFragment.this).navigateUp();
}
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error deleting collection", t);
try {
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
}
catch(final Throwable e) {}
}
});
})
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error deleting collection", t);
try {
final Context context = getContext();
if (context == null) return;
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
} catch (final Throwable ignored) {}
}
}))
.setNegativeButton(R.string.cancel, null)
.show();
}
else if (item.getItemId() == R.id.edit) {
} else if (item.getItemId() == R.id.edit) {
final Context context = getContext();
if (context == null) return false;
final EditText input = new EditText(context);
new AlertDialog.Builder(context)
.setTitle(R.string.edit_collection)
.setView(input)
.setPositiveButton(R.string.confirm, (d, w) -> {
collectionService.editCollectionName(
savedCollection.getId(),
input.getText().toString(),
new ServiceCallback<String>() {
@Override
public void onSuccess(final String result) {
binding.collapsingToolbarLayout.setTitle(input.getText().toString());
SavedCollectionsFragment.pleaseRefresh = true;
}
.setPositiveButton(R.string.confirm, (d, w) -> collectionService.editCollectionName(
savedCollection.getId(),
input.getText().toString(),
new ServiceCallback<String>() {
@Override
public void onSuccess(final String result) {
binding.collapsingToolbarLayout.setTitle(input.getText().toString());
SavedCollectionsFragment.pleaseRefresh = true;
}
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error editing collection", t);
try {
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
}
catch(final Throwable e) {}
}
});
})
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error editing collection", t);
try {
final Context context = getContext();
if (context == null) return;
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
} catch (final Throwable ignored) {}
}
}))
.setNegativeButton(R.string.cancel, null)
.show();
}
@ -443,8 +443,8 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay
private void setupCover() {
final String coverUrl = ResponseBodyUtils.getImageUrl(savedCollection.getCoverMedias() == null
? savedCollection.getCoverMedia()
: savedCollection.getCoverMedias().get(0));
? savedCollection.getCoverMedia()
: savedCollection.getCoverMedias().get(0));
final DraweeController controller = Fresco
.newDraweeControllerBuilder()
.setOldController(binding.cover.getController())

View File

@ -1,5 +1,6 @@
package awais.instagrabber.fragments;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
@ -23,13 +24,14 @@ import androidx.activity.OnBackPressedDispatcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.motion.widget.MotionScene;
import androidx.core.content.PermissionChecker;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.snackbar.BaseTransientBottomBar;
@ -76,9 +78,6 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.settingsHelper;
//import awaisomereport.LogCollector;
//import static awais.instagrabber.utils.Utils.logCollector;
public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "HashTagFragment";
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
@ -88,7 +87,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
private MainActivity fragmentActivity;
private FragmentHashtagBinding binding;
private CoordinatorLayout root;
private MotionLayout root;
private boolean shouldRefresh = true;
private boolean hasStories = false;
private boolean opening = false;
@ -227,17 +226,15 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
return;
}
opening = true;
final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
final NavController navController = NavHostFragment.findNavController(HashTagFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
final FragmentManager fragmentManager = getChildFragmentManager();
if (fragmentManager.isDestroyed()) return;
builder.build().show(fragmentManager, "post_view");
opening = false;
}
};
@ -307,13 +304,11 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
if (root != null) {
shouldRefresh = false;
fragmentActivity.setCollapsingView(hashtagDetailsBinding.getRoot());
return root;
}
binding = FragmentHashtagBinding.inflate(inflater, container, false);
root = binding.getRoot();
hashtagDetailsBinding = LayoutHashtagDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false);
fragmentActivity.setCollapsingView(hashtagDetailsBinding.getRoot());
hashtagDetailsBinding = binding.header;
return root;
}
@ -370,14 +365,6 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (hashtagDetailsBinding != null) {
fragmentActivity.removeCollapsingView(hashtagDetailsBinding.getRoot());
}
}
private void init() {
if (getArguments() == null) return;
final HashTagFragmentArgs fragmentArgs = HashTagFragmentArgs.fromBundle(getArguments());
@ -402,6 +389,17 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
.setSelectionModeCallback(selectionModeCallback)
.init();
binding.swipeRefreshLayout.setRefreshing(true);
binding.posts.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
final boolean canScrollVertically = recyclerView.canScrollVertically(-1);
final MotionScene.Transition transition = root.getTransition(R.id.transition);
if (transition != null) {
transition.setEnable(!canScrollVertically);
}
}
});
}
private void setHashtagDetails() {
@ -428,47 +426,49 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
final long userId = CookieUtils.getUserIdFromCookie(cookie);
final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
if (csrfToken != null && userId != 0 && deviceUuid != null) {
if (csrfToken != null && userId != 0) {
hashtagDetailsBinding.btnFollowTag.setClickable(false);
tagsService.changeFollow(hashtagModel.getFollowing() == FollowingType.FOLLOWING ? "unfollow" : "follow",
hashtag,
csrfToken,
userId,
deviceUuid,
new ServiceCallback<Boolean>() {
@Override
public void onSuccess(final Boolean result) {
hashtagDetailsBinding.btnFollowTag.setClickable(true);
if (!result) {
Log.e(TAG, "onSuccess: result is false");
Snackbar.make(root, R.string.downloader_unknown_error, BaseTransientBottomBar.LENGTH_LONG)
.show();
return;
}
hashtagDetailsBinding.btnFollowTag.setText(R.string.unfollow);
hashtagDetailsBinding.btnFollowTag.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24);
}
tagsService.changeFollow(
hashtagModel.getFollowing() == FollowingType.FOLLOWING ? "unfollow" : "follow",
hashtag,
csrfToken,
userId,
deviceUuid,
new ServiceCallback<Boolean>() {
@Override
public void onSuccess(final Boolean result) {
hashtagDetailsBinding.btnFollowTag.setClickable(true);
if (!result) {
Log.e(TAG, "onSuccess: result is false");
Snackbar.make(root, R.string.downloader_unknown_error, BaseTransientBottomBar.LENGTH_LONG)
.show();
return;
}
hashtagDetailsBinding.btnFollowTag.setText(R.string.unfollow);
hashtagDetailsBinding.btnFollowTag.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24);
}
@Override
public void onFailure(@NonNull final Throwable t) {
hashtagDetailsBinding.btnFollowTag.setClickable(true);
Log.e(TAG, "onFailure: ", t);
final String message = t.getMessage();
Snackbar.make(root,
message != null ? message
: getString(R.string.downloader_unknown_error),
BaseTransientBottomBar.LENGTH_LONG)
.show();
}
});
return;
@Override
public void onFailure(@NonNull final Throwable t) {
hashtagDetailsBinding.btnFollowTag.setClickable(true);
Log.e(TAG, "onFailure: ", t);
final String message = t.getMessage();
Snackbar.make(
root,
message != null ? message : getString(R.string.downloader_unknown_error),
BaseTransientBottomBar.LENGTH_LONG)
.show();
}
});
}
});
} else {
hashtagDetailsBinding.btnFollowTag.setVisibility(View.GONE);
}
hashtagDetailsBinding.favChip.setVisibility(View.VISIBLE);
final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
final Context context = getContext();
if (context == null) return;
final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context));
favoriteRepository.getFavorite(hashtag, FavoriteType.HASHTAG, new RepositoryCallback<Favorite>() {
@Override
public void onSuccess(final Favorite result) {
@ -557,7 +557,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
}
private void showSnackbar(final String message) {
final Snackbar snackbar = Snackbar.make(root, message, BaseTransientBottomBar.LENGTH_LONG);
@SuppressLint("ShowToast") final Snackbar snackbar = Snackbar.make(root, message, BaseTransientBottomBar.LENGTH_LONG);
snackbar.setAction(R.string.ok, v1 -> snackbar.dismiss())
.setAnimationMode(BaseTransientBottomBar.ANIMATION_MODE_SLIDE)
.setAnchorView(fragmentActivity.getBottomNavView())

View File

@ -22,13 +22,14 @@ import androidx.activity.OnBackPressedDispatcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.motion.widget.MotionScene;
import androidx.core.content.PermissionChecker;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.snackbar.BaseTransientBottomBar;
@ -73,9 +74,6 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.settingsHelper;
//import awaisomereport.LogCollector;
//import static awais.instagrabber.utils.Utils.logCollector;
public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "LocationFragment";
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
@ -83,7 +81,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
private MainActivity fragmentActivity;
private FragmentLocationBinding binding;
private CoordinatorLayout root;
private MotionLayout root;
private boolean shouldRefresh = true;
private boolean hasStories = false;
private boolean opening = false;
@ -219,18 +217,15 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
return;
}
opening = true;
final PostViewV2Fragment.Builder builder = PostViewV2Fragment
.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
final NavController navController = NavHostFragment.findNavController(LocationFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
final FragmentManager fragmentManager = getChildFragmentManager();
if (fragmentManager.isDestroyed()) return;
builder.build().show(fragmentManager, "post_view");
opening = false;
}
};
@ -302,13 +297,11 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
@Nullable final Bundle savedInstanceState) {
if (root != null) {
shouldRefresh = false;
fragmentActivity.setCollapsingView(locationDetailsBinding.getRoot());
return root;
}
binding = FragmentLocationBinding.inflate(inflater, container, false);
root = binding.getRoot();
locationDetailsBinding = LayoutLocationDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false);
fragmentActivity.setCollapsingView(locationDetailsBinding.getRoot());
locationDetailsBinding = binding.header;
return root;
}
@ -365,14 +358,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (locationDetailsBinding != null) {
fragmentActivity.removeCollapsingView(locationDetailsBinding.getRoot());
}
}
private void init() {
if (getArguments() == null) return;
final LocationFragmentArgs fragmentArgs = LocationFragmentArgs.fromBundle(getArguments());
@ -393,6 +378,17 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
.setSelectionModeCallback(selectionModeCallback)
.init();
binding.swipeRefreshLayout.setRefreshing(true);
binding.posts.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
final boolean canScrollVertically = recyclerView.canScrollVertically(-1);
final MotionScene.Transition transition = root.getTransition(R.id.transition);
if (transition != null) {
transition.setEnable(!canScrollVertically);
}
}
});
}
private void fetchLocationModel() {

View File

@ -20,6 +20,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -94,8 +95,8 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
final long mediaId = Long.parseLong(notificationImage.getId().split("_")[0]);
if (model.getType() == NotificationType.RESPONDED_STORY) {
final StoryViewerOptions options = StoryViewerOptions.forStory(
mediaId,
model.getArgs().getUsername());
mediaId,
model.getArgs().getUsername());
final Bundle bundle = new Bundle();
bundle.putSerializable("options", options);
NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(R.id.action_notifications_to_story, bundle);
@ -108,11 +109,14 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
mediaService.fetch(mediaId, new ServiceCallback<Media>() {
@Override
public void onSuccess(final Media feedModel) {
final PostViewV2Fragment fragment = PostViewV2Fragment
.builder(feedModel)
.build();
fragment.setOnShowListener(dialog -> alertDialog.dismiss());
fragment.show(getChildFragmentManager(), "post_view");
final NavController navController = NavHostFragment.findNavController(NotificationsViewerFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "onSuccess: ", e);
}
}
@Override

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
@ -50,6 +51,7 @@ import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class SavedViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = SavedViewerFragment.class.getSimpleName();
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030;
@ -171,16 +173,15 @@ public final class SavedViewerFragment extends Fragment implements SwipeRefreshL
final View profilePicView,
final View mainPostImage,
final int position) {
final PostViewV2Fragment.Builder builder = PostViewV2Fragment
.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
final NavController navController = NavHostFragment.findNavController(SavedViewerFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
builder.build().show(getChildFragmentManager(), "post_view");
}
};
private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {

View File

@ -36,6 +36,7 @@ import androidx.core.view.GestureDetectorCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -484,11 +485,14 @@ public class StoryViewerFragment extends Fragment {
mediaService.fetch(Long.parseLong(mediaId), new ServiceCallback<Media>() {
@Override
public void onSuccess(final Media feedModel) {
final PostViewV2Fragment fragment = PostViewV2Fragment
.builder(feedModel)
.build();
fragment.setOnShowListener(dialog -> alertDialog.dismiss());
fragment.show(getChildFragmentManager(), "post_view");
final NavController navController = NavHostFragment.findNavController(StoryViewerFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
}
@Override
@ -503,18 +507,18 @@ public class StoryViewerFragment extends Fragment {
if (tag instanceof PollModel) {
poll = (PollModel) tag;
if (poll.getMyChoice() > -1) {
new AlertDialog.Builder(context).setTitle(R.string.voted_story_poll)
.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1,
new String[]{
(poll.getMyChoice() == 0 ? "" : "") + poll
.getLeftChoice() + " (" + poll
.getLeftCount() + ")",
(poll.getMyChoice() == 1 ? "" : "") + poll
.getRightChoice() + " (" + poll
.getRightCount() + ")"
}), null)
.setPositiveButton(R.string.ok, null)
.show();
new AlertDialog.Builder(context)
.setTitle(R.string.voted_story_poll)
.setAdapter(new ArrayAdapter<>(
context,
android.R.layout.simple_list_item_1,
new String[]{
(poll.getMyChoice() == 0 ? "" : "") + poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
(poll.getMyChoice() == 1 ? "" : "") + poll.getRightChoice() + " (" + poll.getRightCount() + ")"
}),
null)
.setPositiveButton(R.string.ok, null)
.show();
} else {
new AlertDialog.Builder(context)
.setTitle(poll.getQuestion())

View File

@ -10,6 +10,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
@ -51,8 +52,8 @@ import awais.instagrabber.databinding.FragmentTopicPostsBinding;
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
import awais.instagrabber.fragments.main.DiscoverFragmentDirections;
import awais.instagrabber.models.PostsLayoutPreferences;
import awais.instagrabber.repositories.responses.discover.TopicCluster;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.discover.TopicCluster;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.ResponseBodyUtils;
@ -63,6 +64,7 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = TopicPostsFragment.class.getSimpleName();
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030;
@ -182,16 +184,15 @@ public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.O
final View profilePicView,
final View mainPostImage,
final int position) {
final PostViewV2Fragment.Builder builder = PostViewV2Fragment
.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
final NavController navController = NavHostFragment.findNavController(TopicPostsFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
builder.build().show(getChildFragmentManager(), "post_view");
}
};
private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {

View File

@ -96,7 +96,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
}
}
@SuppressLint("UnsafeExperimentalUsageError")
@SuppressLint({"UnsafeExperimentalUsageError", "UnsafeOptInUsageError"})
@Override
public void onPause() {
super.onPause();
@ -176,7 +176,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
if (inboxAdapter == null) return;
inboxAdapter.submitList(list, () -> {
if (!scrollToTop) return;
binding.inboxList.smoothScrollToPosition(0);
binding.inboxList.post(() -> binding.inboxList.smoothScrollToPosition(0));
scrollToTop = false;
});
};
@ -204,7 +204,7 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
viewModel.getPendingRequestsTotal().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge);
}
@SuppressLint("UnsafeExperimentalUsageError")
@SuppressLint({"UnsafeExperimentalUsageError", "UnsafeOptInUsageError"})
private void attachPendingRequestsBadge(@Nullable final Integer count) {
if (pendingRequestsMenuItem == null) {
final Handler handler = new Handler();

View File

@ -15,7 +15,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@ -33,7 +32,6 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
@ -75,6 +73,8 @@ import awais.instagrabber.animations.CubicBezierInterpolator;
import awais.instagrabber.customviews.RecordView;
import awais.instagrabber.customviews.Tooltip;
import awais.instagrabber.customviews.emoji.Emoji;
import awais.instagrabber.customviews.emoji.EmojiBottomSheetDialog;
import awais.instagrabber.customviews.emoji.EmojiPicker;
import awais.instagrabber.customviews.helpers.HeaderItemDecoration;
import awais.instagrabber.customviews.helpers.HeightProvider;
import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtEdge;
@ -114,7 +114,8 @@ import awais.instagrabber.viewmodels.factories.DirectThreadViewModelFactory;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
public class DirectMessageThreadFragment extends Fragment implements DirectReactionsAdapter.OnReactionClickListener {
public class DirectMessageThreadFragment extends Fragment implements DirectReactionsAdapter.OnReactionClickListener,
EmojiPicker.OnEmojiClickListener {
private static final String TAG = DirectMessageThreadFragment.class.getSimpleName();
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
private static final int AUDIO_RECORD_PERM_REQUEST_CODE = 1000;
@ -159,6 +160,9 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
private LiveData<Integer> pendingRequestsCountLiveData;
private LiveData<List<User>> usersLiveData;
private boolean autoMarkAsSeen = false;
private MenuItem markAsSeenMenuItem;
private Media tempMedia;
private DirectItem addReactionItem;
private final AppExecutors appExecutors = AppExecutors.getInstance();
private final Animatable2Compat.AnimationCallback micToSendAnimationCallback = new Animatable2Compat.AnimationCallback() {
@ -224,8 +228,14 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
}
return;
}
final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(media);
builder.build().show(getChildFragmentManager(), "post_view");
final NavController navController = NavHostFragment.findNavController(DirectMessageThreadFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
}
@Override
@ -285,6 +295,14 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
cb.apply(item);
}
}
@Override
public void onAddReactionListener(final DirectItem item) {
if (item == null) return;
addReactionItem = item;
final EmojiBottomSheetDialog emojiBottomSheetDialog = EmojiBottomSheetDialog.newInstance();
emojiBottomSheetDialog.show(getChildFragmentManager(), EmojiBottomSheetDialog.TAG);
}
};
private final DirectItemLongClickListener directItemLongClickListener = position -> {
@ -315,8 +333,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
backStackSavedStateResultLiveData.postValue(null);
};
private final MutableLiveData<Integer> inputLength = new MutableLiveData<>(0);
private MenuItem markAsSeenMenuItem;
private Media tempMedia;
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
@ -327,11 +343,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
final Bundle arguments = getArguments();
if (arguments == null) return;
final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments);
final User currentUser = appStateViewModel.getCurrentUser();
if (currentUser == null) return;
final DirectThreadViewModelFactory viewModelFactory = new DirectThreadViewModelFactory(
fragmentActivity.getApplication(),
fragmentArgs.getThreadId(),
fragmentArgs.getPending(),
appStateViewModel.getCurrentUser()
currentUser
);
viewModel = new ViewModelProvider(this, viewModelFactory).get(DirectThreadViewModel.class);
setHasOptionsMenu(true);
@ -386,7 +404,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
final DirectMessageThreadFragmentDirections.ActionThreadToSettings directions = DirectMessageThreadFragmentDirections
.actionThreadToSettings(viewModel.getThreadId(), null);
final Boolean pending = viewModel.isPending().getValue();
directions.setPending(pending == null ? false : pending);
directions.setPending(pending != null && pending);
NavHostFragment.findNavController(this).navigate(directions);
return true;
}
@ -414,14 +432,10 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
case SUCCESS:
Toast.makeText(context, R.string.marked_as_seen, Toast.LENGTH_SHORT).show();
case LOADING:
if (item != null) {
item.setEnabled(false);
}
item.setEnabled(false);
break;
case ERROR:
if (item != null) {
item.setEnabled(true);
}
item.setEnabled(true);
if (resource.message != null) {
Snackbar.make(context, binding.getRoot(), resource.message, Snackbar.LENGTH_LONG).show();
return;
@ -1352,7 +1366,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE);
}
@NonNull
@Nullable
private User getUser(final long userId) {
for (final User user : users) {
if (userId != user.getPk()) continue;
@ -1457,25 +1471,12 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(direction);
}
public static class ItemsAdapterDataMerger extends MediatorLiveData<Pair<User, DirectThread>> {
private User user;
private DirectThread thread;
public ItemsAdapterDataMerger(final LiveData<User> userLiveData,
final LiveData<DirectThread> threadLiveData) {
addSource(userLiveData, user -> {
this.user = user;
combine();
});
addSource(threadLiveData, thread -> {
this.thread = thread;
combine();
});
}
private void combine() {
if (user == null || thread == null) return;
setValue(new Pair<>(user, thread));
@Override
public void onClick(final View view, final Emoji emoji) {
if (addReactionItem == null) return;
final LiveData<Resource<Object>> resourceLiveData = viewModel.sendReaction(addReactionItem, emoji);
if (resourceLiveData != null) {
resourceLiveData.observe(getViewLifecycleOwner(), directItemResource -> handleSentMessage(resourceLiveData));
}
}
}

View File

@ -18,7 +18,8 @@ import androidx.activity.OnBackPressedCallback;
import androidx.activity.OnBackPressedDispatcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.motion.widget.MotionScene;
import androidx.core.content.PermissionChecker;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
@ -29,7 +30,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.common.collect.ImmutableList;
import java.util.List;
@ -64,7 +64,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030;
private MainActivity fragmentActivity;
private CoordinatorLayout root;
private MotionLayout root;
private FragmentFeedBinding binding;
private StoriesService storiesService;
private boolean shouldRefresh = true;
@ -179,15 +179,21 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
final View profilePicView,
final View mainPostImage,
final int position) {
final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
// ViewCompat.setTransitionName(profilePicView, "profile_pic");
// ViewCompat.setTransitionName(mainPostImage, "post_image");
// final FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
// .addSharedElement(profilePicView, "profile_pic")
// .addSharedElement(mainPostImage, "post_image")
// .build();
final NavController navController = NavHostFragment.findNavController(FeedFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
builder.build().show(getChildFragmentManager(), "post_view");
}
};
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
@ -278,9 +284,6 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
final Bundle savedInstanceState) {
if (root != null) {
shouldRefresh = false;
if (storiesRecyclerView != null) {
fragmentActivity.setCollapsingView(storiesRecyclerView);
}
return root;
}
binding = FragmentFeedBinding.inflate(inflater, container, false);
@ -381,6 +384,17 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
.setSelectionModeCallback(selectionModeCallback)
.init();
binding.feedSwipeRefreshLayout.setRefreshing(true);
binding.feedRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
final boolean canScrollVertically = recyclerView.canScrollVertically(-1);
final MotionScene.Transition transition = root.getTransition(R.id.transition);
if (transition != null) {
transition.setEnable(!canScrollVertically);
}
}
});
// if (shouldAutoPlay) {
// videoAwareRecyclerScroller = new VideoAwareRecyclerScroller();
// binding.feedRecyclerView.addOnScrollListener(videoAwareRecyclerScroller);
@ -396,15 +410,9 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
feedStoriesViewModel = new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class);
final Context context = getContext();
if (context == null) return;
storiesRecyclerView = new RecyclerView(context);
final CollapsingToolbarLayout.LayoutParams params = new CollapsingToolbarLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, Utils.getActionBarHeight(context), 0, 0);
storiesRecyclerView.setLayoutParams(params);
storiesRecyclerView.setClipToPadding(false);
storiesRecyclerView = binding.header;
storiesRecyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false));
storiesRecyclerView.setAdapter(feedStoriesAdapter);
fragmentActivity.setCollapsingView(storiesRecyclerView);
feedStoriesViewModel.getList().observe(getViewLifecycleOwner(), feedStoriesAdapter::submitList);
fetchStories();
}

View File

@ -27,7 +27,8 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.motion.widget.MotionScene;
import androidx.core.content.PermissionChecker;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@ -108,7 +109,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030;
private MainActivity fragmentActivity;
private CoordinatorLayout root;
private MotionLayout root;
private FragmentProfileBinding binding;
private boolean isLoggedIn;
private String cookie;
@ -250,23 +251,15 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
final View profilePicView,
final View mainPostImage,
final int position) {
final PostViewV2Fragment.Builder builder = PostViewV2Fragment
.builder(feedModel);
if (position >= 0) {
builder.setPosition(position);
final NavController navController = NavHostFragment.findNavController(ProfileFragment.this);
final Bundle bundle = new Bundle();
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position);
try {
navController.navigate(R.id.action_global_post_view, bundle);
} catch (Exception e) {
Log.e(TAG, "openPostDialog: ", e);
}
if (!layoutPreferences.isAnimationDisabled()) {
builder.setSharedProfilePicElement(profilePicView)
.setSharedMainPostElement(mainPostImage);
}
final PostViewV2Fragment postViewV2Fragment = builder.build();
postViewV2Fragment.setOnDeleteListener(() -> {
postViewV2Fragment.dismiss();
binding.postsRecyclerView.refresh();
});
final FragmentManager fragmentManager = getChildFragmentManager();
if (fragmentManager.isDestroyed() || fragmentManager.isStateSaved()) return;
postViewV2Fragment.show(fragmentManager, "post_view");
}
};
private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() {
@ -345,26 +338,22 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
final boolean isSame = ("@" + profileModelUsername).equals(this.username);
if (isSame) {
setUsernameDelayed();
fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
shouldRefresh = false;
return root;
}
}
if (username == null || !username.equals(this.username)) {
fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
shouldRefresh = true;
return root;
}
}
setUsernameDelayed();
fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
shouldRefresh = false;
return root;
}
binding = FragmentProfileBinding.inflate(inflater, container, false);
root = binding.getRoot();
profileDetailsBinding = LayoutProfileDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false);
fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot());
profileDetailsBinding = binding.header;
return root;
}
@ -554,14 +543,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (profileDetailsBinding != null) {
fragmentActivity.removeCollapsingView(profileDetailsBinding.getRoot());
}
}
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
@ -589,7 +570,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
setUsernameDelayed();
}
if (TextUtils.isEmpty(username) && !isLoggedIn) {
profileDetailsBinding.infoContainer.setVisibility(View.GONE);
binding.header.getRoot().setVisibility(View.GONE);
binding.swipeRefreshLayout.setEnabled(false);
binding.privatePage1.setImageResource(R.drawable.ic_outline_info_24);
binding.privatePage2.setText(R.string.no_acc);
@ -1209,6 +1190,17 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
.setFeedItemCallback(feedItemCallback)
.setSelectionModeCallback(selectionModeCallback)
.init();
binding.postsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
final boolean canScrollVertically = recyclerView.canScrollVertically(-1);
final MotionScene.Transition transition = root.getTransition(R.id.transition);
if (transition != null) {
transition.setEnable(!canScrollVertically);
}
}
});
binding.swipeRefreshLayout.setRefreshing(true);
postsSetupDone = true;
}

View File

@ -7,4 +7,5 @@ public final class PreferenceKeys {
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number";
public static final String PREF_ENABLE_SENTRY = "enable_sentry";
public static final String PREF_TAB_ORDER = "tab_order";
public static final String PREF_SHOWN_COUNT_TOOLTIP = "shown_count_tooltip";
}

View File

@ -585,8 +585,7 @@ public final class ThreadManager {
if (index < 0) {
temp.add(0, reaction);
} else if (shouldReplaceIfAlreadyReacted) {
temp.add(0, reaction);
temp.remove(index);
temp.set(index, reaction);
}
return temp;
}
@ -736,6 +735,7 @@ public final class ThreadManager {
});
}
@NonNull
public LiveData<Resource<Object>> sendReaction(final DirectItem item, final Emoji emoji) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
final Long userId = getCurrentUserId(data);

View File

@ -111,6 +111,9 @@ public class User implements Serializable {
}
public String getHDProfilePicUrl() {
if (hdProfilePicUrlInfo == null) {
return getProfilePicUrl();
}
return hdProfilePicUrlInfo.getUrl();
}

View File

@ -47,4 +47,14 @@ public class DirectItemEmojiReaction implements Serializable {
public int hashCode() {
return Objects.hash(senderId, timestamp, emoji, superReactType);
}
@Override
public String toString() {
return "DirectItemEmojiReaction{" +
"senderId=" + senderId +
", timestamp=" + timestamp +
", emoji='" + emoji + '\'' +
", superReactType='" + superReactType + '\'' +
'}';
}
}

View File

@ -51,4 +51,12 @@ public class DirectItemReactions implements Cloneable, Serializable {
public int hashCode() {
return Objects.hash(emojis, likes);
}
@Override
public String toString() {
return "DirectItemReactions{" +
"emojis=" + emojis +
", likes=" + likes +
'}';
}
}

View File

@ -36,11 +36,6 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback {
}
}
public void setIconSize(int width, int height) {
iconWidth = width;
iconHeight = height;
}
public CombinedDrawable(Drawable backgroundDrawable, Drawable iconDrawable) {
background = backgroundDrawable;
icon = iconDrawable;
@ -49,6 +44,11 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback {
}
}
public void setIconSize(int width, int height) {
iconWidth = width;
iconHeight = height;
}
public void setCustomSize(int width, int height) {
backWidth = width;
backHeight = height;
@ -82,11 +82,12 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback {
}
@Override
public boolean setState(int[] stateSet) {
public boolean setState(@NonNull int[] stateSet) {
icon.setState(stateSet);
return true;
}
@NonNull
@Override
public int[] getState() {
return icon.getState();
@ -108,7 +109,7 @@ public class CombinedDrawable extends Drawable implements Drawable.Callback {
}
@Override
public void draw(Canvas canvas) {
public void draw(@NonNull Canvas canvas) {
background.setBounds(getBounds());
background.draw(canvas);
if (icon != null) {

View File

@ -13,6 +13,7 @@ import java.util.Optional;
import awais.instagrabber.R;
import awais.instagrabber.models.enums.DirectItemType;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
import awais.instagrabber.repositories.responses.directmessages.DirectItemAnimatedMedia;
@ -26,11 +27,6 @@ public final class DMUtils {
public static boolean isRead(@NonNull final DirectItem item,
@NonNull final Map<Long, DirectThreadLastSeenAt> lastSeenAt,
@NonNull final List<Long> userIdsToCheck) {
// Further check if directStory exists
// if (read && directStory != null) {
// read = false;
// }
if (item == null) return false;
return lastSeenAt.entrySet()
.stream()
.filter(entry -> userIdsToCheck.contains(entry.getKey()))
@ -57,7 +53,7 @@ public final class DMUtils {
read = true;
} else {
final Map<Long, DirectThreadLastSeenAt> lastSeenAtMap = thread.getLastSeenAt();
read = isRead(item, lastSeenAtMap, Collections.singletonList(viewerId));
read = item != null && isRead(item, lastSeenAtMap, Collections.singletonList(viewerId));
}
return read;
}
@ -88,7 +84,11 @@ public final class DMUtils {
message = item.getPlaceholder().getMessage();
break;
case MEDIA_SHARE:
final User mediaShareUser = item.getMediaShare().getUser();
final Media mediaShare = item.getMediaShare();
User mediaShareUser = null;
if (mediaShare != null) {
mediaShareUser = mediaShare.getUser();
}
subtitle = resources.getString(R.string.dms_inbox_shared_post,
username != null ? username : "",
mediaShareUser == null ? "" : mediaShareUser.getUsername());
@ -120,7 +120,11 @@ public final class DMUtils {
final int format = reelType.equals("highlight_reel")
? R.string.dms_inbox_shared_highlight
: R.string.dms_inbox_shared_story;
final User storyShareMediaUser = item.getStoryShare().getMedia().getUser();
final Media media = item.getStoryShare().getMedia();
User storyShareMediaUser = null;
if (media != null) {
storyShareMediaUser = media.getUser();
}
subtitle = resources.getString(format,
username != null ? username : "",
storyShareMediaUser == null ? "" : storyShareMediaUser.getUsername());
@ -137,13 +141,21 @@ public final class DMUtils {
subtitle = item.getVideoCallEvent().getDescription();
break;
case CLIP:
final User clipUser = item.getClip().getClip().getUser();
final Media clip = item.getClip().getClip();
User clipUser = null;
if (clip != null) {
clipUser = clip.getUser();
}
subtitle = resources.getString(R.string.dms_inbox_shared_clip,
username != null ? username : "",
clipUser == null ? "" : clipUser.getUsername());
break;
case FELIX_SHARE:
final User felixShareVideoUser = item.getFelixShare().getVideo().getUser();
final Media video = item.getFelixShare().getVideo();
User felixShareVideoUser = null;
if (video != null) {
felixShareVideoUser = video.getUser();
}
subtitle = resources.getString(R.string.dms_inbox_shared_igtv,
username != null ? username : "",
felixShareVideoUser == null ? "" : felixShareVideoUser.getUsername());

View File

@ -21,6 +21,7 @@ import com.google.android.material.bottomnavigation.BottomNavigationView;
import java.util.List;
import awais.instagrabber.R;
import awais.instagrabber.customviews.NavHostFragmentWithDefaultAnimations;
import awais.instagrabber.fragments.main.FeedFragment;
/**
@ -139,7 +140,7 @@ public class NavigationExtensions {
if (existingFragment != null) {
return existingFragment;
}
final NavHostFragment navHostFragment = NavHostFragment.create(navGraphId);
final NavHostFragment navHostFragment = NavHostFragmentWithDefaultAnimations.create(navGraphId);
fragmentManager.beginTransaction()
.setReorderingAllowed(true)
.add(containerId, navHostFragment, fragmentTag)

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);
}
}

View File

@ -1,8 +1,9 @@
package awais.instagrabber.utils;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import androidx.annotation.Nullable;
import java.util.Locale;
import java.util.Random;
public final class NumberUtils {
@ -56,7 +57,7 @@ public final class NumberUtils {
}
@NonNull
public static Pair<Integer, Integer> calculateWidthHeight(final int height, final int width, final int maxHeight, final int maxWidth) {
public static NullSafePair<Integer, Integer> calculateWidthHeight(final int height, final int width, final int maxHeight, final int maxWidth) {
if (width > maxWidth) {
int tempHeight = getResultingHeight(maxWidth, height, width);
int tempWidth = maxWidth;
@ -64,7 +65,7 @@ public final class NumberUtils {
tempWidth = getResultingWidth(maxHeight, tempHeight, tempWidth);
tempHeight = maxHeight;
}
return new Pair<>(tempWidth, tempHeight);
return new NullSafePair<>(tempWidth, tempHeight);
}
if ((height < maxHeight && width < maxWidth) || (height > maxHeight)) {
int tempWidth = getResultingWidth(maxHeight, height, width);
@ -73,12 +74,76 @@ public final class NumberUtils {
tempHeight = getResultingHeight(maxWidth, tempHeight, tempWidth);
tempWidth = maxWidth;
}
return new Pair<>(tempWidth, tempHeight);
return new NullSafePair<>(tempWidth, tempHeight);
}
return new Pair<>(width, height);
return new NullSafePair<>(width, height);
}
public static float roundFloat2Decimals(final float value) {
return ((int) ((value + (value >= 0 ? 1 : -1) * 0.005f) * 100)) / 100f;
}
@NonNull
public static String abbreviate(final long number) {
return abbreviate(number, null);
}
@NonNull
public static String abbreviate(final long number, @Nullable final AbbreviateOptions options) {
// adapted from https://stackoverflow.com/a/9769590/1436766
int threshold = 1000;
boolean addSpace = false;
if (options != null) {
threshold = options.getThreshold();
addSpace = options.addSpaceBeforePrefix();
}
if (number < threshold) return "" + number;
int exp = (int) (Math.log(number) / Math.log(threshold));
return String.format(Locale.US,
"%.1f%s%c",
number / Math.pow(threshold, exp),
addSpace ? " " : "",
"kMGTPE".charAt(exp - 1));
}
public static final class AbbreviateOptions {
private final int threshold;
private final boolean addSpaceBeforePrefix;
public static final class Builder {
private int threshold = 1000;
private boolean addSpaceBeforePrefix = false;
public Builder setThreshold(final int threshold) {
this.threshold = threshold;
return this;
}
public Builder setAddSpaceBeforePrefix(final boolean addSpaceBeforePrefix) {
this.addSpaceBeforePrefix = addSpaceBeforePrefix;
return this;
}
@NonNull
public AbbreviateOptions build() {
return new AbbreviateOptions(threshold, addSpaceBeforePrefix);
}
}
private AbbreviateOptions(final int threshold, final boolean addSpaceBeforePrefix) {
this.threshold = threshold;
this.addSpaceBeforePrefix = addSpaceBeforePrefix;
}
public int getThreshold() {
return threshold;
}
public boolean addSpaceBeforePrefix() {
return addSpaceBeforePrefix;
}
}
}

View File

@ -16,6 +16,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT;
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS;
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY;
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_SHOWN_COUNT_TOOLTIP;
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_TAB_ORDER;
import static awais.instagrabber.utils.Constants.APP_LANGUAGE;
import static awais.instagrabber.utils.Constants.APP_THEME;
@ -165,7 +166,7 @@ public final class SettingsHelper {
@StringDef({DOWNLOAD_USER_FOLDER, DOWNLOAD_PREPEND_USER_NAME, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY,
CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH,
FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS, PLAY_IN_BACKGROUND})
FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY, HIDE_MUTED_REELS, PLAY_IN_BACKGROUND, PREF_SHOWN_COUNT_TOOLTIP})
public @interface BooleanSettings {}
@StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER})

View File

@ -10,6 +10,7 @@ import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.MediaScannerConnection;
@ -22,6 +23,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
@ -288,6 +290,18 @@ public final class Utils {
return outValue.data;
}
public static int getAttrValue(@NonNull final Context context, final int attr) {
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(attr, outValue, true);
return outValue.data;
}
public static int getAttrResId(@NonNull final Context context, final int attr) {
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(attr, outValue, true);
return outValue.resourceId;
}
public static void transparentStatusBar(final Activity activity,
final boolean enable,
final boolean fullscreen) {
@ -511,4 +525,41 @@ public final class Utils {
if (navRootString == null || tabOrderString == null) return false;
return tabOrderString.contains(navRootString);
}
@NonNull
public static Point getNavigationBarSize(@NonNull Context context) {
Point appUsableSize = getAppUsableScreenSize(context);
Point realScreenSize = getRealScreenSize(context);
// navigation bar on the right
if (appUsableSize.x < realScreenSize.x) {
return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
}
// navigation bar at the bottom
if (appUsableSize.y < realScreenSize.y) {
return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
}
// navigation bar is not present
return new Point();
}
@NonNull
public static Point getAppUsableScreenSize(@NonNull Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
@NonNull
public static Point getRealScreenSize(@NonNull Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
return size;
}
}

View File

@ -15,6 +15,7 @@ import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@ -77,7 +78,12 @@ public final class EmojiParser {
.addAll(emoji.getVariants())
.build()
.stream())
.collect(Collectors.toMap(Emoji::getUnicode, Function.identity()));
.collect(Collectors.toMap(
Emoji::getUnicode,
Function.identity(),
(u, v) -> u,
LinkedHashMap::new
));
} catch (Exception e) {
Log.e(TAG, "EmojiParser: ", e);
}

View File

@ -65,6 +65,7 @@ public class IgErrorsInterceptor implements Interceptor {
if (body == null) return;
try {
final String bodyString = body.string();
Log.d(TAG, "checkError: " + bodyString);
final JSONObject jsonObject = new JSONObject(bodyString);
String message = jsonObject.optString("message");
if (!TextUtils.isEmpty(message)) {

View File

@ -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>

View File

@ -1,10 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="300"
android:fromXDelta="100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
</set>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="100%"
android:toXDelta="0%" />

View File

@ -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>

View File

@ -1,10 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="300"
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="100%"
android:toYDelta="0%" />
</set>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="0%"
android:toXDelta="100%" />

View File

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333">
<path
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:viewportHeight="24">
<path
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" />
</vector>

View File

@ -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>

View File

@ -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>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/black" />
<solid android:color="@android:color/transparent" />
</shape>

View File

@ -1,477 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_a80">
android:background="?colorSurface"
tools:context=".fragments.PostViewV2Fragment">
<awais.instagrabber.customviews.drawee.DraggableZoomableDraweeView
android:id="@+id/post_image"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:clickable="true"
android:focusable="true"
android:transitionName="post_image"
app:actualImageScaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@mipmap/ic_launcher"
tools:visibility="visible" />
android:layout_height="wrap_content">
<include
android:id="@+id/video_post"
layout="@layout/layout_video_player_with_thumbnail"
android:visibility="gone" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/slider_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:visibility="visible" />
<View
android:id="@+id/top_bg"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/black_a80"
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<awais.instagrabber.customviews.ProfilePicView
android:id="@+id/profile_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:transitionName="profile_pic"
app:layout_constraintBottom_toBottomOf="@id/top_bg"
app:layout_constraintEnd_toStartOf="@id/title"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/top_bg"
app:size="regular" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
android:textColor="@color/white"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/subtitle"
app:layout_constraintEnd_toStartOf="@id/options"
app:layout_constraintStart_toEndOf="@id/profile_pic"
app:layout_constraintTop_toTopOf="@id/profile_pic"
tools:text="Username Username Username" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
app:layout_constraintEnd_toStartOf="@id/options"
app:layout_constraintStart_toStartOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/title"
tools:text="Full name Full name Full name Full name Full name Full name Full name " />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/options"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/top_bg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/top_bg"
app:srcCompat="@drawable/ic_more_vert_24"
app:tint="@color/white"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Group
android:id="@+id/user_details_group"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="top_bg, profile_pic,title,subtitle,options"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/media_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="@drawable/rounder_corner_semi_black_bg"
android:gravity="center"
android:padding="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
android:textColor="@android:color/white"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/top_bg"
tools:text="1/5"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/location"
style="?borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:elevation="0dp"
android:ellipsize="end"
android:insetTop="0dp"
android:insetBottom="0dp"
android:maxWidth="200dp"
android:maxLines="1"
android:minHeight="32dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="@android:color/white"
android:visibility="gone"
app:backgroundTint="@color/black_a50"
app:elevation="0dp"
app:icon="@drawable/ic_round_location_on_24"
app:iconSize="16dp"
app:iconTint="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/top_bg"
app:rippleColor="@color/grey_600"
tools:text="Location, Location, Location, Location, "
tools:visibility="visible" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@null"
app:layout_constraintBottom_toBottomOf="@id/bottom_bg_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible">
<androidx.core.widget.NestedScrollView
android:id="@+id/caption_parent"
android:layout_width="match_parent"
<awais.instagrabber.customviews.ProfilePicView
android:id="@+id/profile_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/black_a80"
app:behavior_hideable="true"
app:behavior_peekHeight="100dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
android:layout_margin="12dp"
android:transitionName="profile_pic"
app:layout_constraintBottom_toTopOf="@id/top_barrier"
app:layout_constraintEnd_toStartOf="@id/title"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:size="regular" />
<ScrollView
android:id="@+id/bottom_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/subtitle"
app:layout_constraintEnd_toStartOf="@id/options"
app:layout_constraintStart_toEndOf="@id/profile_pic"
app:layout_constraintTop_toTopOf="@id/profile_pic"
tools:text="Username Username Username" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
app:layout_constraintEnd_toStartOf="@id/options"
app:layout_constraintStart_toStartOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/title"
tools:text="Full name Full name Full name Full name Full name Full name Full name "
tools:visibility="gone" />
<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="16dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/white"
tools:text="Text text text" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/options"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/profile_pic"
app:srcCompat="@drawable/ic_more_vert_24"
tools:visibility="visible" />
<!--<androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/editCaption"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginStart="16dp"-->
<!-- android:layout_marginTop="8dp"-->
<!-- android:background="@null"-->
<!-- android:gravity="center_vertical"-->
<!-- android:text="@string/edit_caption"-->
<!-- android:textColor="?android:textColorSecondary"-->
<!-- android:textSize="16sp"-->
<!-- android:visibility="gone"-->
<!-- app:layout_constraintBottom_toTopOf="@id/translatedCaption"-->
<!-- app:layout_constraintTop_toBottomOf="@id/caption"-->
<!-- tools:visibility="visible" />-->
<androidx.constraintlayout.widget.Barrier
android:id="@+id/top_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierAllowsGoneWidgets="true"
app:barrierDirection="bottom" />
<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:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:text="@string/translate_caption"
android:textColor="@color/blue_600"
android:textSize="16sp"
android:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/media_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="@drawable/rounder_corner_semi_black_bg"
android:gravity="center"
android:padding="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
android:textColor="@android:color/white"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_pic"
tools:text="1/5"
tools:visibility="visible" />
<!--<awais.instagrabber.customviews.RamboTextViewV2-->
<!-- android:id="@+id/translatedCaption"-->
<!-- 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="16dp"-->
<!-- android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"-->
<!-- android:textColor="@color/white"-->
<!-- android:visibility="gone"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/translateTitle"-->
<!-- tools:text="Text text text"-->
<!-- tools:visibility="visible" />-->
</LinearLayout>
</ScrollView>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/location"
style="?borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:elevation="0dp"
android:ellipsize="end"
android:insetTop="0dp"
android:insetBottom="0dp"
android:maxWidth="200dp"
android:maxLines="1"
android:minHeight="32dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="@android:color/white"
android:visibility="gone"
app:backgroundTint="@color/black_a50"
app:elevation="0dp"
app:icon="@drawable/ic_round_location_on_24"
app:iconSize="16dp"
app:iconTint="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_pic"
app:rippleColor="@color/grey_600"
tools:text="Location, Location, Location, Location, "
tools:visibility="visible" />
<!--<include-->
<!-- android:id="@+id/player_controls"-->
<!-- layout="@layout/layout_exo_custom_controls"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:visibility="gone"-->
<!-- app:layout_constraintBottom_toTopOf="@id/bottom_bg_barrier"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- tools:visibility="gone" />-->
<include layout="@layout/layout_post_view_bottom" />
<View
android:id="@+id/bottom_bg"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/black_a80"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/bottom_bg_barrier" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bottom_bg_barrier"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="true"
app:barrierDirection="top"
app:constraint_referenced_ids="likes_count,comments_count,views_count" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/likes_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@id/counts_barrier"
app:layout_constraintEnd_toStartOf="@id/comments_count"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bottom_bg_barrier"
tools:text="9999999999 likes"
tools:visibility="gone" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/comments_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@id/counts_barrier"
app:layout_constraintEnd_toStartOf="@id/views_count"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/likes_count"
app:layout_constraintTop_toBottomOf="@id/bottom_bg_barrier"
tools:text="9999999 comments"
tools:visibility="gone" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/views_count"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@id/counts_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/comments_count"
app:layout_constraintTop_toBottomOf="@id/bottom_bg_barrier"
tools:text="9999999999 views"
tools:visibility="gone" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/counts_barrier"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="true"
app:barrierDirection="top"
app:constraint_referenced_ids="date" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@id/buttons_barrier"
app:layout_constraintTop_toBottomOf="@id/counts_barrier"
tools:text="2020-11-07 11:18:55"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/buttons_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="true"
app:barrierDirection="bottom"
app:constraint_referenced_ids="date" />
<com.google.android.material.button.MaterialButton
android:id="@+id/caption_toggle"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:visibility="visible"
app:icon="@drawable/ic_notes_24"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/like"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/like"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:visibility="visible"
app:icon="@drawable/ic_not_liked"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/comment"
app:layout_constraintStart_toEndOf="@id/caption_toggle"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/comment"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:visibility="visible"
app:icon="@drawable/ic_outline_comments_24"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/save"
app:layout_constraintStart_toEndOf="@id/like"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300"
tools:visibility="visible" />
<!--<com.google.android.material.button.MaterialButton-->
<!-- android:id="@+id/player_controls_toggle"-->
<!-- style="@style/Widget.MaterialComponents.Button.TextButton"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="48dp"-->
<!-- android:visibility="gone"-->
<!-- app:icon="@drawable/ic_play_circle_outline_24"-->
<!-- app:iconGravity="textStart"-->
<!-- app:iconPadding="0dp"-->
<!-- app:iconSize="24dp"-->
<!-- app:iconTint="@color/white"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toStartOf="@id/save"-->
<!-- app:layout_constraintStart_toEndOf="@id/comment"-->
<!-- app:layout_constraintTop_toBottomOf="@id/buttons_barrier"-->
<!-- app:rippleColor="@color/grey_300"-->
<!-- tools:visibility="visible" />-->
<com.google.android.material.button.MaterialButton
android:id="@+id/save"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:visibility="visible"
app:icon="@drawable/ic_outline_class_24"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/share"
app:layout_constraintStart_toEndOf="@id/comment"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/share"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:visibility="visible"
app:icon="?attr/actionModeShareDrawable"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/download"
app:layout_constraintStart_toEndOf="@id/save"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/download"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:visibility="visible"
app:icon="@drawable/ic_download"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/share"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -15,6 +15,7 @@
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="?attr/toolbarColor"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<FrameLayout
@ -39,6 +40,7 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@null"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>

View File

@ -10,12 +10,15 @@
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="?attr/actionBarSize"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/topics_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
tools:itemCount="10"

View File

@ -1,40 +1,39 @@
<?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:tools="http://schemas.android.com/tools"
android:layout_width="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-->
<!-- android:id="@+id/stories_container"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content">-->
<!-- <com.google.android.material.appbar.CollapsingToolbarLayout-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_scrollFlags="scroll|snap">-->
<!--<androidx.recyclerview.widget.RecyclerView-->
<!-- 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.recyclerview.widget.RecyclerView
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarColor"
android:clipToPadding="false"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@id/feed_swipe_refresh_layout"
app:layout_constraintTop_toTopOf="parent"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_highlight" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/feed_swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:layout_height="0dp"
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
android:id="@+id/feed_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
tools:listitem="@layout/item_feed_photo" />
tools:listitem="@layout/item_feed_grid" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>

View File

@ -1,15 +1,28 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
android:background="?attr/colorSurface"
app:layoutDescription="@xml/header_list_scene">
<include
android:id="@+id/header"
layout="@layout/layout_hashtag_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/swipe_refresh_layout"
app:layout_constraintTop_toTopOf="parent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:layout_height="0dp"
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
android:id="@+id/posts"
@ -17,4 +30,4 @@
android:layout_height="match_parent"
android:clipToPadding="false" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>

View File

@ -1,15 +1,28 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
android:background="?attr/colorSurface"
app:layoutDescription="@xml/header_list_scene">
<include
android:id="@+id/header"
layout="@layout/layout_location_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/swipe_refresh_layout"
app:layout_constraintTop_toTopOf="parent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:layout_height="0dp"
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
android:id="@+id/posts"
@ -17,4 +30,4 @@
android:layout_height="match_parent"
android:clipToPadding="false" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>

View File

@ -1,33 +1,29 @@
<?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:tools="http://schemas.android.com/tools"
android:layout_width="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-->
<!-- android:id="@+id/appBarLayout"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:background="?attr/colorSurface"-->
<!-- app:elevation="0dp"-->
<!-- app:layout_scrollFlags="scroll">-->
<!-- <com.google.android.material.appbar.CollapsingToolbarLayout-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_scrollFlags="scroll">-->
<!-- <include layout="@layout/layout_profile_details" />-->
<!-- </com.google.android.material.appbar.CollapsingToolbarLayout>-->
<!--</com.google.android.material.appbar.AppBarLayout>-->
<include
android:id="@+id/header"
layout="@layout/layout_profile_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/swipe_refresh_layout"
app:layout_constraintTop_toTopOf="parent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:layout_height="0dp"
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
android:id="@+id/posts_recycler_view"
@ -62,4 +58,4 @@
android:text="@string/priv_acc"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>

View File

@ -15,6 +15,7 @@
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="?attr/toolbarColor"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<FrameLayout
@ -39,6 +40,7 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@null"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>

View File

@ -20,6 +20,7 @@
android:gravity="center"
android:maxLines="1"
android:padding="2dp"
android:scrollbars="none"
android:singleLine="true"
android:textColor="?attr/colorOnPrimarySurface"
android:textStyle="bold"

View File

@ -139,7 +139,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:layout_height="200dp"
tools:layout_width="100dp" />
tools:layout_width="100dp">
<!--<include layout="@layout/layout_dm_text" />-->
</FrameLayout>
<LinearLayout
android:id="@+id/message_info"
@ -176,6 +178,17 @@
</awais.instagrabber.customviews.ChatMessageLayout>
<!--<TextView-->
<!-- android:tag="debug"-->
<!-- android:textColor="@color/white"-->
<!-- android:layout_width="0dp"-->
<!-- android:visibility="visible"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:background="@color/black"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"/>-->
<FrameLayout
android:id="@+id/reactions_wrapper"
android:layout_width="0dp"

View File

@ -10,4 +10,4 @@
android:paddingBottom="@dimen/dm_message_card_radius_small"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/white"
tools:text="Text message" />
tools:text="So here you can see the timestamp overlaps lol tt tt tt tt tt tt tt tt tt tt t" />

View File

@ -4,8 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- android:padding="8dp"
android:background="@color/black_a80"-->
<View
android:layout_width="0dp"
@ -14,69 +12,13 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--<androidx.constraintlayout.widget.Barrier-->
<!-- android:id="@+id/top_barrier"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="0dp"-->
<!-- app:barrierDirection="top" />-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@id/exo_progress"
app:layout_constraintEnd_toStartOf="@id/exo_progress"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/exo_progress"
tools:text="0:00" />
<!--<com.google.android.material.slider.Slider-->
<!-- android:id="@+id/timeline"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:contentDescription="@string/player_timeline_desc"-->
<!-- android:enabled="false"-->
<!-- android:value="0"-->
<!-- android:valueFrom="0.0"-->
<!-- android:valueTo="1.0"-->
<!-- app:labelStyle="@style/Widget.MaterialComponents.Tooltip.ExoPlayer"-->
<!-- app:layout_constraintBottom_toTopOf="@id/play_pause"-->
<!-- app:layout_constraintEnd_toStartOf="@id/to_time"-->
<!-- app:layout_constraintStart_toEndOf="@id/from_time"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:thumbColor="@color/white"-->
<!-- app:trackColorActive="@color/white"-->
<!-- app:trackColorInactive="@color/grey_800" />-->
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@+id/exo_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/progress_barrier"
app:layout_constraintEnd_toStartOf="@id/exo_duration"
app:layout_constraintStart_toEndOf="@id/exo_position"
app:layout_constraintVertical_bias="1"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@id/exo_progress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/exo_progress"
app:layout_constraintTop_toTopOf="@id/exo_progress"
tools:text="0:00" />
app:layout_constraintTop_toTopOf="@id/top_barrier" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/progress_barrier"
android:id="@+id/top_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom" />
app:barrierDirection="top" />
<com.google.android.material.button.MaterialButton
android:id="@+id/exo_rew_with_amount"
@ -87,31 +29,26 @@
app:icon="@drawable/ic_replay_5_24_states"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintBottom_toTopOf="@id/progress_barrier"
app:layout_constraintEnd_toStartOf="@id/exo_play_pause"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
app:layout_constraintTop_toBottomOf="@id/top_barrier"
tools:enabled="false"
tools:visibility="visible" />
tools:visibility="gone" />
<!--
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
app:icon="@drawable/ic_play_states"
app:iconSize="24dp"
app:iconTint="@color/white"
-->
<androidx.appcompat.widget.AppCompatImageView
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/exo_play_pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:background="@drawable/background_grey_ripple"
android:contentDescription="@string/exo_controls_play_description"
android:padding="@dimen/exo_icon_padding"
android:padding="8dp"
android:scaleType="fitCenter"
android:src="@drawable/exo_styled_controls_play"
app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintBottom_toTopOf="@id/progress_barrier"
app:layout_constraintEnd_toStartOf="@id/exo_ffwd_with_amount"
app:layout_constraintStart_toEndOf="@id/exo_rew_with_amount"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
app:layout_constraintTop_toBottomOf="@id/top_barrier"
tools:enabled="false"
tools:visibility="visible" />
@ -123,12 +60,12 @@
app:icon="@drawable/ic_forward_5_24_states"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintBottom_toTopOf="@id/progress_barrier"
app:layout_constraintEnd_toStartOf="@id/mute"
app:layout_constraintStart_toEndOf="@id/exo_play_pause"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
app:layout_constraintTop_toBottomOf="@id/top_barrier"
tools:enabled="false"
tools:visibility="visible" />
tools:visibility="gone" />
<com.google.android.material.button.MaterialButton
android:id="@+id/mute"
@ -138,10 +75,10 @@
app:icon="@drawable/ic_volume_off_24_states"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintBottom_toTopOf="@id/progress_barrier"
app:layout_constraintEnd_toStartOf="@id/exo_settings"
app:layout_constraintStart_toEndOf="@id/exo_ffwd_with_amount"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
app:layout_constraintTop_toBottomOf="@id/top_barrier"
tools:enabled="false"
tools:visibility="visible" />
@ -153,32 +90,53 @@
app:icon="@drawable/exo_ic_settings"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintBottom_toTopOf="@id/progress_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/mute"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
app:layout_constraintTop_toBottomOf="@id/top_barrier"
tools:enabled="false"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/bottom_barrier"
<androidx.constraintlayout.widget.Barrier
android:id="@+id/progress_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_end="200dp" />
app:barrierDirection="top" />
<!--<com.google.android.material.button.MaterialButton-->
<!-- android:id="@+id/speed"-->
<!-- style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/one_x"-->
<!-- android:textAllCaps="false"-->
<!-- android:textColor="@drawable/speed_text_color_states"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toEndOf="@id/mute"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- tools:enabled="false"-->
<!-- tools:visibility="visible" />-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/exo_progress"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:text="0:00"
tools:visibility="gone" />
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@+id/exo_progress"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/exo_duration"
app:layout_constraintStart_toEndOf="@id/exo_position"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
app:layout_constraintVertical_bias="1"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/exo_progress"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:text="0:00"
tools:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,10 +2,9 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tagInfoContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
android:background="?toolbarColor"
android:padding="@dimen/profile_info_container_bottom_space">
<awais.instagrabber.customviews.CircularImageView

View File

@ -2,11 +2,10 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/locInfoContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
android:animateLayoutChanges="true"
android:background="?toolbarColor"
android:padding="8dp">
<awais.instagrabber.customviews.CircularImageView
@ -20,20 +19,20 @@
app:layout_constraintTop_toTopOf="parent"
tools:background="@mipmap/ic_launcher" />
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/mainLocPostCount"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="0dp"-->
<!-- android:gravity="center_vertical"-->
<!-- android:maxLines="1"-->
<!-- android:paddingStart="12dp"-->
<!-- android:paddingEnd="12dp"-->
<!-- android:textAppearance="@style/TextAppearance.AppCompat"-->
<!-- app:layout_constraintBottom_toTopOf="@id/btnMap"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toEndOf="@id/mainLocationImage"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- tools:text="35 Posts" />-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/mainLocPostCount"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="0dp"-->
<!-- android:gravity="center_vertical"-->
<!-- android:maxLines="1"-->
<!-- android:paddingStart="12dp"-->
<!-- android:paddingEnd="12dp"-->
<!-- android:textAppearance="@style/TextAppearance.AppCompat"-->
<!-- app:layout_constraintBottom_toTopOf="@id/btnMap"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toEndOf="@id/mainLocationImage"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- tools:text="35 Posts" />-->
<com.google.android.material.chip.Chip
android:id="@+id/btnMap"
@ -44,8 +43,8 @@
app:chipBackgroundColor="@null"
app:chipIcon="@drawable/ic_outline_map_24"
app:chipIconTint="@color/green_500"
app:layout_constraintTop_toTopOf="@id/mainLocationImage"
app:layout_constraintStart_toEndOf="@id/mainLocationImage"
app:layout_constraintTop_toTopOf="@id/mainLocationImage"
app:rippleColor="@color/grey_500"
tools:visibility="visible" />
@ -86,8 +85,8 @@
android:id="@+id/locationBiography"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="?android:selectableItemBackground"
android:padding="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -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>

View File

@ -2,10 +2,9 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/infoContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize">
android:background="?toolbarColor">
<awais.instagrabber.customviews.CircularImageView
android:id="@+id/mainProfileImage"
@ -326,9 +325,9 @@
<androidx.constraintlayout.widget.Barrier
android:id="@+id/highlights_barrier"
android:layout_width="wrap_content"
app:constraint_referenced_ids="mainPostCount, mainFollowers, mainFollowing"
android:layout_height="wrap_content"
app:barrierDirection="bottom" />
app:barrierDirection="bottom"
app:constraint_referenced_ids="mainPostCount, mainFollowers, mainFollowing" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/highlightsList"

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ViewSwitcher xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -15,7 +14,7 @@
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actualImageScaleType="centerCrop"
app:actualImageScaleType="fitCenter"
app:viewAspectRatio="1" />
<androidx.appcompat.widget.AppCompatImageView
@ -25,28 +24,13 @@
app:srcCompat="@drawable/ic_video_24" />
</FrameLayout>
<FrameLayout
<!--app:controller_layout_id="@layout/layout_exo_custom_controls"-->
<com.google.android.exoplayer2.ui.StyledPlayerView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.exoplayer2.ui.StyledPlayerView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
app:animation_enabled="false"
app:controller_layout_id="@layout/layout_exo_custom_controls"
app:resize_mode="fit"
app:show_timeout="1500"
app:use_controller="true" />
<!--<com.google.android.exoplayer2.ui.StyledPlayerControlView-->
<!-- android:id="@+id/controls"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- app:controller_layout_id="@layout/layout_exo_custom_controls"-->
<!-- app:show_fastforward_button="false"-->
<!-- app:show_rewind_button="false"-->
<!-- app:show_timeout="3000" />-->
</FrameLayout>
android:layout_height="match_parent"
android:layout_gravity="center"
app:resize_mode="fixed_width"
app:show_timeout="2000"
app:use_controller="true" />
</ViewSwitcher>

View File

@ -4,15 +4,15 @@
<item
android:id="@+id/edit"
android:icon="@android:drawable/ic_menu_edit"
android:icon="@drawable/ic_round_edit_24"
android:title="@string/edit_collection"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/delete"
android:icon="@android:drawable/ic_menu_delete"
android:icon="@drawable/ic_delete"
android:title="@string/delete_collection"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/layout"

View File

@ -100,6 +100,18 @@
android:id="@+id/action_global_search"
app:destination="@id/searchFragment" />
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/directMessagesInboxFragment"
android:name="awais.instagrabber.fragments.directmessages.DirectMessageInboxFragment"
@ -191,10 +203,14 @@
android:id="@+id/action_pending_inbox_to_thread"
app:destination="@id/directMessagesThreadFragment" />
</fragment>
<fragment
android:id="@+id/searchFragment"
android:name="awais.instagrabber.fragments.search.SearchFragment"
android:label="@string/search"
tools:layout="@layout/fragment_search" />
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -99,6 +99,18 @@
android:id="@+id/action_global_search"
app:destination="@id/searchFragment" />
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/discoverFragment"
android:name="awais.instagrabber.fragments.main.DiscoverFragment"
@ -129,4 +141,9 @@
android:name="awais.instagrabber.fragments.search.SearchFragment"
android:label="@string/search"
tools:layout="@layout/fragment_search" />
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -110,6 +110,18 @@
android:id="@+id/action_global_search"
app:destination="@id/searchFragment" />
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/feedFragment"
android:name="awais.instagrabber.fragments.main.FeedFragment"
@ -133,4 +145,9 @@
android:name="awais.instagrabber.fragments.search.SearchFragment"
android:label="@string/search"
tools:layout="@layout/fragment_search" />
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -69,6 +69,18 @@
android:id="@+id/action_global_search"
app:destination="@id/searchFragment" />
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/hashTagFragment"
android:name="awais.instagrabber.fragments.HashTagFragment"
@ -104,4 +116,9 @@
app:argType="string"
app:nullable="false" />
</action>
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -70,6 +70,18 @@
android:id="@+id/action_global_search"
app:destination="@id/searchFragment" />
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/locationFragment"
android:name="awais.instagrabber.fragments.LocationFragment"
@ -103,4 +115,9 @@
android:name="awais.instagrabber.fragments.search.SearchFragment"
android:label="@string/search"
tools:layout="@layout/fragment_search" />
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -72,6 +72,18 @@
app:argType="boolean" />
</action>
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/storyViewerFragment"
android:name="awais.instagrabber.fragments.StoryViewerFragment"
@ -100,4 +112,9 @@
android:id="@+id/action_notifications_to_story"
app:destination="@id/storyViewerFragment" />
</fragment>
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -86,6 +86,18 @@
app:destination="@id/storyViewerFragment" />
</action>
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/notificationsViewer"
android:name="awais.instagrabber.fragments.NotificationsViewerFragment"
@ -93,9 +105,9 @@
tools:layout="@layout/fragment_notifications_viewer">
<argument
android:name="type"
android:defaultValue="notif"
app:argType="string"
app:nullable="false"
android:defaultValue="notif"/>
app:nullable="false" />
<argument
android:name="targetId"
android:defaultValue="0L"
@ -197,4 +209,9 @@
android:name="awais.instagrabber.fragments.search.SearchFragment"
android:label="@string/search"
tools:layout="@layout/fragment_search" />
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -64,15 +64,27 @@
app:nullable="false" />
</action>
<action
android:id="@+id/action_global_post_view"
app:destination="@id/postViewFragment">
<argument
android:name="media"
app:argType="awais.instagrabber.repositories.responses.Media"
app:nullable="false" />
<argument
android:name="position"
app:argType="integer" />
</action>
<fragment
android:id="@+id/savedCollectionsFragment"
android:name="awais.instagrabber.fragments.SavedCollectionsFragment"
android:label="@string/saved"
tools:layout="@layout/fragment_saved_collections" >
tools:layout="@layout/fragment_saved_collections">
<argument
android:name="isSaving"
app:argType="boolean"
android:defaultValue="false" />
android:defaultValue="false"
app:argType="boolean" />
<action
android:id="@+id/action_savedCollectionsFragment_to_collectionPostsFragment"
app:destination="@id/collectionPostsFragment" />
@ -93,4 +105,9 @@
android:name="backgroundColor"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/postViewFragment"
android:name="awais.instagrabber.fragments.PostViewV2Fragment"
android:label="Post"
tools:layout="@layout/dialog_post_view" />
</navigation>

View File

@ -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>

View File

@ -503,5 +503,7 @@
<string name="recent">Recent</string>
<string name="clear">Clear</string>
<string name="no_external_map_app">No Map app found!</string>
<string name="click_to_show_full">Click to view full count</string>
<string name="no_profile_pic_found">No profile pic found!</string>
<string name="swipe_up_confirmation">Are you sure you want to open this link?</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More