Browse Source
Add Kotlin and convert some model classes to kotlin
renovate/org.robolectric-robolectric-4.x
Add Kotlin and convert some model classes to kotlin
renovate/org.robolectric-robolectric-4.x
54 changed files with 589 additions and 1297 deletions
-
1app/build.gradle
-
2app/src/main/java/awais/instagrabber/activities/MainActivity.java
-
9app/src/main/java/awais/instagrabber/adapters/FeedStoriesAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java
-
6app/src/main/java/awais/instagrabber/adapters/viewholder/FilterViewHolder.java
-
8app/src/main/java/awais/instagrabber/customviews/Tooltip.java
-
6app/src/main/java/awais/instagrabber/customviews/emoji/EmojiGridAdapter.java
-
4app/src/main/java/awais/instagrabber/customviews/emoji/EmojiVariantManager.java
-
2app/src/main/java/awais/instagrabber/customviews/emoji/EmojiVariantPopup.java
-
3app/src/main/java/awais/instagrabber/customviews/emoji/ReactionsManager.java
-
26app/src/main/java/awais/instagrabber/db/repositories/AccountRepository.java
-
26app/src/main/java/awais/instagrabber/db/repositories/DMLastNotifiedRepository.java
-
18app/src/main/java/awais/instagrabber/db/repositories/FavoriteRepository.java
-
22app/src/main/java/awais/instagrabber/db/repositories/RecentSearchRepository.java
-
2app/src/main/java/awais/instagrabber/dialogs/AccountSwitcherDialogFragment.java
-
8app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
-
10app/src/main/java/awais/instagrabber/fragments/imageedit/FiltersFragment.java
-
2app/src/main/java/awais/instagrabber/fragments/imageedit/ImageEditFragment.java
-
7app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java
-
117app/src/main/java/awais/instagrabber/models/Comment.java
-
69app/src/main/java/awais/instagrabber/models/Comment.kt
-
78app/src/main/java/awais/instagrabber/models/FeedStoryModel.java
-
20app/src/main/java/awais/instagrabber/models/FeedStoryModel.kt
-
68app/src/main/java/awais/instagrabber/models/FollowModel.java
-
49app/src/main/java/awais/instagrabber/models/FollowModel.kt
-
52app/src/main/java/awais/instagrabber/models/HighlightModel.java
-
15app/src/main/java/awais/instagrabber/models/HighlightModel.kt
-
21app/src/main/java/awais/instagrabber/models/IntentModel.java
-
5app/src/main/java/awais/instagrabber/models/IntentModel.kt
-
64app/src/main/java/awais/instagrabber/models/Resource.java
-
36app/src/main/java/awais/instagrabber/models/Resource.kt
-
66app/src/main/java/awais/instagrabber/models/SavedImageEditState.java
-
13app/src/main/java/awais/instagrabber/models/SavedImageEditState.kt
-
110app/src/main/java/awais/instagrabber/models/Tab.java
-
36app/src/main/java/awais/instagrabber/models/Tab.kt
-
97app/src/main/java/awais/instagrabber/models/UploadPhotoOptions.java
-
9app/src/main/java/awais/instagrabber/models/UploadPhotoOptions.kt
-
217app/src/main/java/awais/instagrabber/models/UploadVideoOptions.java
-
22app/src/main/java/awais/instagrabber/models/UploadVideoOptions.kt
-
106app/src/main/java/awais/instagrabber/utils/AppExecutors.java
-
52app/src/main/java/awais/instagrabber/utils/AppExecutors.kt
-
14app/src/main/java/awais/instagrabber/utils/BitmapUtils.java
-
20app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
-
4app/src/main/java/awais/instagrabber/utils/FlavorTown.java
-
6app/src/main/java/awais/instagrabber/utils/MediaController.java
-
173app/src/main/java/awais/instagrabber/utils/MediaUploadHelper.java
-
154app/src/main/java/awais/instagrabber/utils/MediaUploadHelper.kt
-
10app/src/main/java/awais/instagrabber/utils/MediaUploader.java
-
4app/src/main/java/awais/instagrabber/utils/MediaUtils.java
-
2app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java
-
2app/src/main/java/awais/instagrabber/viewmodels/ImageEditViewModel.java
-
2app/src/main/java/awais/instagrabber/viewmodels/SearchFragmentViewModel.java
-
6app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
-
3build.gradle
@ -1,117 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Date; |
|
||||
import java.util.Objects; |
|
||||
|
|
||||
import awais.instagrabber.repositories.responses.User; |
|
||||
import awais.instagrabber.utils.Utils; |
|
||||
|
|
||||
public class Comment implements Serializable, Cloneable { |
|
||||
private final User user; |
|
||||
private final String id; |
|
||||
private final String text; |
|
||||
private long likes; |
|
||||
private final long timestamp; |
|
||||
private boolean liked; |
|
||||
private final int replyCount; |
|
||||
private final boolean isChild; |
|
||||
|
|
||||
public Comment(final String id, |
|
||||
final String text, |
|
||||
final long timestamp, |
|
||||
final long likes, |
|
||||
final boolean liked, |
|
||||
final User user, |
|
||||
final int replyCount, final boolean isChild) { |
|
||||
this.id = id; |
|
||||
this.text = text; |
|
||||
this.likes = likes; |
|
||||
this.liked = liked; |
|
||||
this.timestamp = timestamp; |
|
||||
this.user = user; |
|
||||
this.replyCount = replyCount; |
|
||||
this.isChild = isChild; |
|
||||
} |
|
||||
|
|
||||
public String getId() { |
|
||||
return id; |
|
||||
} |
|
||||
|
|
||||
public String getText() { |
|
||||
return text; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public String getDateTime() { |
|
||||
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
|
||||
} |
|
||||
|
|
||||
public long getLikes() { |
|
||||
return likes; |
|
||||
} |
|
||||
|
|
||||
public boolean getLiked() { |
|
||||
return liked; |
|
||||
} |
|
||||
|
|
||||
public void setLiked(boolean liked) { |
|
||||
this.likes = liked ? likes + 1 : likes - 1; |
|
||||
this.liked = liked; |
|
||||
} |
|
||||
|
|
||||
public User getUser() { |
|
||||
return user; |
|
||||
} |
|
||||
|
|
||||
public int getReplyCount() { |
|
||||
return replyCount; |
|
||||
} |
|
||||
|
|
||||
public boolean isChild() { |
|
||||
return isChild; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
@Override |
|
||||
public Object clone() throws CloneNotSupportedException { |
|
||||
return super.clone(); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean equals(final Object o) { |
|
||||
if (this == o) return true; |
|
||||
if (o == null || getClass() != o.getClass()) return false; |
|
||||
final Comment comment = (Comment) o; |
|
||||
return likes == comment.likes && |
|
||||
timestamp == comment.timestamp && |
|
||||
liked == comment.liked && |
|
||||
replyCount == comment.replyCount && |
|
||||
Objects.equals(user, comment.user) && |
|
||||
Objects.equals(id, comment.id) && |
|
||||
Objects.equals(text, comment.text) && |
|
||||
isChild == comment.isChild; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public int hashCode() { |
|
||||
return Objects.hash(user, id, text, likes, timestamp, liked, replyCount, isChild); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "Comment{" + |
|
||||
"user=" + user + |
|
||||
", id='" + id + '\'' + |
|
||||
", text='" + text + '\'' + |
|
||||
", likes=" + likes + |
|
||||
", timestamp=" + timestamp + |
|
||||
", liked=" + liked + |
|
||||
", replyCount" + replyCount + |
|
||||
", isChild" + isChild + |
|
||||
'}'; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,69 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import awais.instagrabber.repositories.responses.User |
||||
|
import awais.instagrabber.utils.Utils |
||||
|
import java.io.Serializable |
||||
|
import java.util.* |
||||
|
|
||||
|
class Comment( |
||||
|
val id: String, |
||||
|
val text: String, |
||||
|
val timestamp: Long, |
||||
|
var likes: Long, |
||||
|
private var liked: Boolean, |
||||
|
val user: User, |
||||
|
val replyCount: Int, |
||||
|
val isChild: Boolean, |
||||
|
) : Serializable, Cloneable { |
||||
|
val dateTime: String |
||||
|
get() = Utils.datetimeParser.format(Date(timestamp * 1000L)) |
||||
|
|
||||
|
fun getLiked(): Boolean { |
||||
|
return liked |
||||
|
} |
||||
|
|
||||
|
fun setLiked(liked: Boolean) { |
||||
|
likes = if (liked) likes + 1 else likes - 1 |
||||
|
this.liked = liked |
||||
|
} |
||||
|
|
||||
|
@Throws(CloneNotSupportedException::class) |
||||
|
public override fun clone(): Any { |
||||
|
return super.clone() |
||||
|
} |
||||
|
|
||||
|
|
||||
|
override fun equals(other: Any?): Boolean { |
||||
|
if (this === other) return true |
||||
|
if (javaClass != other?.javaClass) return false |
||||
|
|
||||
|
other as Comment |
||||
|
|
||||
|
if (id != other.id) return false |
||||
|
if (text != other.text) return false |
||||
|
if (timestamp != other.timestamp) return false |
||||
|
if (likes != other.likes) return false |
||||
|
if (liked != other.liked) return false |
||||
|
if (user != other.user) return false |
||||
|
if (replyCount != other.replyCount) return false |
||||
|
if (isChild != other.isChild) return false |
||||
|
|
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
override fun hashCode(): Int { |
||||
|
var result = id.hashCode() |
||||
|
result = 31 * result + text.hashCode() |
||||
|
result = 31 * result + timestamp.hashCode() |
||||
|
result = 31 * result + likes.hashCode() |
||||
|
result = 31 * result + liked.hashCode() |
||||
|
result = 31 * result + user.hashCode() |
||||
|
result = 31 * result + replyCount |
||||
|
result = 31 * result + isChild.hashCode() |
||||
|
return result |
||||
|
} |
||||
|
|
||||
|
override fun toString(): String { |
||||
|
return "Comment(id='$id', text='$text', timestamp=$timestamp, likes=$likes, liked=$liked, user=$user, replyCount=$replyCount, isChild=$isChild)" |
||||
|
} |
||||
|
} |
@ -1,78 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Date; |
|
||||
|
|
||||
import awais.instagrabber.repositories.responses.User; |
|
||||
import awais.instagrabber.utils.Utils; |
|
||||
|
|
||||
public final class FeedStoryModel implements Serializable { |
|
||||
private final String storyMediaId; |
|
||||
private final User profileModel; |
|
||||
private final StoryModel firstStoryModel; |
|
||||
private Boolean fullyRead; |
|
||||
private final boolean isLive, isBestie; |
|
||||
private final long timestamp; |
|
||||
private final int mediaCount; |
|
||||
|
|
||||
public FeedStoryModel(final String storyMediaId, |
|
||||
final User profileModel, |
|
||||
final boolean fullyRead, |
|
||||
final long timestamp, |
|
||||
final StoryModel firstStoryModel, |
|
||||
final int mediaCount, |
|
||||
final boolean isLive, |
|
||||
final boolean isBestie) { |
|
||||
this.storyMediaId = storyMediaId; |
|
||||
this.profileModel = profileModel; |
|
||||
this.fullyRead = fullyRead; |
|
||||
this.timestamp = timestamp; |
|
||||
this.firstStoryModel = firstStoryModel; |
|
||||
this.mediaCount = mediaCount; |
|
||||
this.isLive = isLive; |
|
||||
this.isBestie = isBestie; |
|
||||
} |
|
||||
|
|
||||
public String getStoryMediaId() { |
|
||||
return storyMediaId; |
|
||||
} |
|
||||
|
|
||||
public long getTimestamp() { |
|
||||
return timestamp; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public String getDateTime() { |
|
||||
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
|
||||
} |
|
||||
|
|
||||
public int getMediaCount() { |
|
||||
return mediaCount; |
|
||||
} |
|
||||
|
|
||||
public User getProfileModel() { |
|
||||
return profileModel; |
|
||||
} |
|
||||
|
|
||||
public StoryModel getFirstStoryModel() { |
|
||||
return firstStoryModel; |
|
||||
} |
|
||||
|
|
||||
public Boolean isFullyRead() { |
|
||||
return fullyRead; |
|
||||
} |
|
||||
|
|
||||
public void setFullyRead(final boolean fullyRead) { |
|
||||
this.fullyRead = fullyRead; |
|
||||
} |
|
||||
|
|
||||
public boolean isLive() { |
|
||||
return isLive; |
|
||||
} |
|
||||
|
|
||||
public boolean isBestie() { |
|
||||
return isBestie; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,20 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import awais.instagrabber.repositories.responses.User |
||||
|
import awais.instagrabber.utils.Utils |
||||
|
import java.io.Serializable |
||||
|
import java.util.* |
||||
|
|
||||
|
data class FeedStoryModel( |
||||
|
val storyMediaId: String, |
||||
|
val profileModel: User, |
||||
|
var isFullyRead: Boolean, |
||||
|
val timestamp: Long, |
||||
|
val firstStoryModel: StoryModel, |
||||
|
val mediaCount: Int, |
||||
|
val isLive: Boolean, |
||||
|
val isBestie: Boolean |
||||
|
) : Serializable { |
||||
|
val dateTime: String |
||||
|
get() = Utils.datetimeParser.format(Date(timestamp * 1000L)) |
||||
|
} |
@ -1,68 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import androidx.annotation.Nullable; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
|
|
||||
public final class FollowModel implements Serializable { |
|
||||
private final String id; |
|
||||
private final String username; |
|
||||
private final String fullName; |
|
||||
private final String profilePicUrl; |
|
||||
private String endCursor; |
|
||||
private boolean hasNextPage; |
|
||||
private boolean isShown = true; |
|
||||
|
|
||||
public FollowModel(final String id, final String username, final String fullName, final String profilePicUrl) { |
|
||||
this.id = id; |
|
||||
this.username = username; |
|
||||
this.fullName = fullName; |
|
||||
this.profilePicUrl = profilePicUrl; |
|
||||
} |
|
||||
|
|
||||
public String getId() { |
|
||||
return id; |
|
||||
} |
|
||||
|
|
||||
public String getUsername() { |
|
||||
return username; |
|
||||
} |
|
||||
|
|
||||
public String getFullName() { |
|
||||
return fullName; |
|
||||
} |
|
||||
|
|
||||
public String getProfilePicUrl() { |
|
||||
return profilePicUrl; |
|
||||
} |
|
||||
|
|
||||
public boolean isShown() { |
|
||||
return isShown; |
|
||||
} |
|
||||
|
|
||||
public void setShown(final boolean shown) { |
|
||||
isShown = shown; |
|
||||
} |
|
||||
|
|
||||
public void setPageCursor(final boolean hasNextPage, final String endCursor) { |
|
||||
this.endCursor = endCursor; |
|
||||
this.hasNextPage = hasNextPage; |
|
||||
} |
|
||||
|
|
||||
public boolean hasNextPage() { |
|
||||
return endCursor != null && hasNextPage; |
|
||||
} |
|
||||
|
|
||||
public String getEndCursor() { |
|
||||
return endCursor; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean equals(@Nullable final Object obj) { |
|
||||
if (obj instanceof FollowModel) { |
|
||||
final FollowModel model = (FollowModel) obj; |
|
||||
if (model.getId().equals(id) && model.getUsername().equals(username)) return true; |
|
||||
} |
|
||||
return super.equals(obj); |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,49 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import java.io.Serializable |
||||
|
|
||||
|
class FollowModel( |
||||
|
val id: String, |
||||
|
val username: String, |
||||
|
val fullName: String, |
||||
|
val profilePicUrl: String |
||||
|
) : Serializable { |
||||
|
private var hasNextPage = false |
||||
|
get() = endCursor != null && field |
||||
|
|
||||
|
var isShown = true |
||||
|
|
||||
|
var endCursor: String? = null |
||||
|
private set |
||||
|
|
||||
|
fun setPageCursor(hasNextPage: Boolean, endCursor: String?) { |
||||
|
this.endCursor = endCursor |
||||
|
this.hasNextPage = hasNextPage |
||||
|
} |
||||
|
|
||||
|
override fun equals(other: Any?): Boolean { |
||||
|
if (this === other) return true |
||||
|
if (javaClass != other?.javaClass) return false |
||||
|
|
||||
|
other as FollowModel |
||||
|
|
||||
|
if (id != other.id) return false |
||||
|
if (username != other.username) return false |
||||
|
if (fullName != other.fullName) return false |
||||
|
if (profilePicUrl != other.profilePicUrl) return false |
||||
|
if (isShown != other.isShown) return false |
||||
|
if (endCursor != other.endCursor) return false |
||||
|
|
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
override fun hashCode(): Int { |
||||
|
var result = id.hashCode() |
||||
|
result = 31 * result + username.hashCode() |
||||
|
result = 31 * result + fullName.hashCode() |
||||
|
result = 31 * result + profilePicUrl.hashCode() |
||||
|
result = 31 * result + isShown.hashCode() |
||||
|
result = 31 * result + (endCursor?.hashCode() ?: 0) |
||||
|
return result |
||||
|
} |
||||
|
} |
@ -1,52 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.util.Date; |
|
||||
|
|
||||
import awais.instagrabber.utils.Utils; |
|
||||
|
|
||||
public final class HighlightModel { |
|
||||
private final String title; |
|
||||
private final String id; |
|
||||
private final String thumbnailUrl; |
|
||||
private final long timestamp; |
|
||||
private final int mediaCount; |
|
||||
|
|
||||
public HighlightModel(final String title, |
|
||||
final String id, |
|
||||
final String thumbnailUrl, |
|
||||
final long timestamp, |
|
||||
final int mediaCount) { |
|
||||
this.title = title; |
|
||||
this.id = id; |
|
||||
this.thumbnailUrl = thumbnailUrl; |
|
||||
this.timestamp = timestamp; |
|
||||
this.mediaCount = mediaCount; |
|
||||
} |
|
||||
|
|
||||
public String getTitle() { |
|
||||
return title; |
|
||||
} |
|
||||
|
|
||||
public String getId() { |
|
||||
return id; |
|
||||
} |
|
||||
|
|
||||
public String getThumbnailUrl() { |
|
||||
return thumbnailUrl; |
|
||||
} |
|
||||
|
|
||||
public long getTimestamp() { |
|
||||
return timestamp; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public String getDateTime() { |
|
||||
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
|
||||
} |
|
||||
|
|
||||
public int getMediaCount() { |
|
||||
return mediaCount; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,15 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import awais.instagrabber.utils.Utils |
||||
|
import java.util.* |
||||
|
|
||||
|
data class HighlightModel( |
||||
|
val title: String, |
||||
|
val id: String, |
||||
|
val thumbnailUrl: String, |
||||
|
val timestamp: Long, |
||||
|
val mediaCount: Int |
||||
|
) { |
||||
|
val dateTime: String |
||||
|
get() = Utils.datetimeParser.format(Date(timestamp * 1000L)) |
||||
|
} |
@ -1,21 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import awais.instagrabber.models.enums.IntentModelType; |
|
||||
|
|
||||
public final class IntentModel { |
|
||||
private final IntentModelType type; |
|
||||
private final String text; |
|
||||
|
|
||||
public IntentModel(final IntentModelType type, final String text) { |
|
||||
this.type = type; |
|
||||
this.text = text; |
|
||||
} |
|
||||
|
|
||||
public IntentModelType getType() { |
|
||||
return type; |
|
||||
} |
|
||||
|
|
||||
public String getText() { |
|
||||
return text; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,5 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import awais.instagrabber.models.enums.IntentModelType |
||||
|
|
||||
|
data class IntentModel(val type: IntentModelType, val text: String) |
@ -1,64 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
import androidx.annotation.Nullable; |
|
||||
|
|
||||
import java.util.Objects; |
|
||||
|
|
||||
public class Resource<T> { |
|
||||
public final Status status; |
|
||||
public final T data; |
|
||||
public final String message; |
|
||||
public final int resId; |
|
||||
|
|
||||
private Resource(@NonNull Status status, |
|
||||
@Nullable T data, |
|
||||
@Nullable String message, |
|
||||
int resId) { |
|
||||
this.status = status; |
|
||||
this.data = data; |
|
||||
this.message = message; |
|
||||
this.resId = resId; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static <T> Resource<T> success(@NonNull T data) { |
|
||||
return new Resource<>(Status.SUCCESS, data, null, 0); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static <T> Resource<T> error(String msg, @Nullable T data) { |
|
||||
return new Resource<>(Status.ERROR, data, msg, 0); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static <T> Resource<T> error(int resId, @Nullable T data) { |
|
||||
return new Resource<>(Status.ERROR, data, null, resId); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static <T> Resource<T> loading(@Nullable T data) { |
|
||||
return new Resource<>(Status.LOADING, data, null, 0); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean equals(final Object o) { |
|
||||
if (this == o) return true; |
|
||||
if (o == null || getClass() != o.getClass()) return false; |
|
||||
final Resource<?> resource = (Resource<?>) o; |
|
||||
return status == resource.status && |
|
||||
Objects.equals(data, resource.data) && |
|
||||
Objects.equals(message, resource.message); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public int hashCode() { |
|
||||
return Objects.hash(status, data, message); |
|
||||
} |
|
||||
|
|
||||
public enum Status { |
|
||||
SUCCESS, |
|
||||
ERROR, |
|
||||
LOADING |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,36 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import androidx.annotation.StringRes |
||||
|
|
||||
|
data class Resource<T>( |
||||
|
@JvmField val status: Status, |
||||
|
@JvmField val data: T? = null, |
||||
|
@JvmField val message: String? = null, |
||||
|
@JvmField @StringRes val resId: Int = 0, |
||||
|
) { |
||||
|
enum class Status { |
||||
|
SUCCESS, ERROR, LOADING |
||||
|
} |
||||
|
|
||||
|
companion object { |
||||
|
@JvmStatic |
||||
|
fun <T> success(data: T): Resource<T> { |
||||
|
return Resource(Status.SUCCESS, data, null, 0) |
||||
|
} |
||||
|
|
||||
|
@JvmStatic |
||||
|
fun <T> error(msg: String?, data: T?): Resource<T?> { |
||||
|
return Resource(Status.ERROR, data, msg, 0) |
||||
|
} |
||||
|
|
||||
|
@JvmStatic |
||||
|
fun <T> error(resId: Int, data: T?): Resource<T?> { |
||||
|
return Resource(Status.ERROR, data, null, resId) |
||||
|
} |
||||
|
|
||||
|
@JvmStatic |
||||
|
fun <T> loading(data: T?): Resource<T?> { |
||||
|
return Resource(Status.LOADING, data, null, 0) |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,66 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import android.graphics.RectF; |
|
||||
|
|
||||
import java.util.HashMap; |
|
||||
import java.util.Map; |
|
||||
|
|
||||
import awais.instagrabber.fragments.imageedit.filters.FiltersHelper; |
|
||||
import awais.instagrabber.utils.SerializablePair; |
|
||||
|
|
||||
public class SavedImageEditState { |
|
||||
|
|
||||
private final String sessionId; |
|
||||
private final String originalPath; |
|
||||
|
|
||||
private float[] cropImageMatrixValues; // 9 values of matrix |
|
||||
private RectF cropRect; |
|
||||
private HashMap<FiltersHelper.FilterType, Map<Integer, Object>> appliedTuningFilters; |
|
||||
private SerializablePair<FiltersHelper.FilterType, Map<Integer, Object>> appliedFilter; |
|
||||
|
|
||||
public SavedImageEditState(final String sessionId, String originalPath) { |
|
||||
this.sessionId = sessionId; |
|
||||
this.originalPath = originalPath; |
|
||||
} |
|
||||
|
|
||||
public String getSessionId() { |
|
||||
return sessionId; |
|
||||
} |
|
||||
|
|
||||
public String getOriginalPath() { |
|
||||
return originalPath; |
|
||||
} |
|
||||
|
|
||||
public float[] getCropImageMatrixValues() { |
|
||||
return cropImageMatrixValues; |
|
||||
} |
|
||||
|
|
||||
public void setCropImageMatrixValues(float[] cropImageMatrixValues) { |
|
||||
this.cropImageMatrixValues = cropImageMatrixValues; |
|
||||
} |
|
||||
|
|
||||
public RectF getCropRect() { |
|
||||
return cropRect; |
|
||||
} |
|
||||
|
|
||||
public void setCropRect(RectF cropRect) { |
|
||||
this.cropRect = cropRect; |
|
||||
} |
|
||||
|
|
||||
public HashMap<FiltersHelper.FilterType, Map<Integer, Object>> getAppliedTuningFilters() { |
|
||||
return appliedTuningFilters; |
|
||||
} |
|
||||
|
|
||||
public void setAppliedTuningFilters(final HashMap<FiltersHelper.FilterType, Map<Integer, Object>> appliedTuningFilters) { |
|
||||
this.appliedTuningFilters = appliedTuningFilters; |
|
||||
} |
|
||||
|
|
||||
public SerializablePair<FiltersHelper.FilterType, Map<Integer, Object>> getAppliedFilter() { |
|
||||
return appliedFilter; |
|
||||
} |
|
||||
|
|
||||
public void setAppliedFilter(final SerializablePair<FiltersHelper.FilterType, Map<Integer, Object>> appliedFilter) { |
|
||||
this.appliedFilter = appliedFilter; |
|
||||
} |
|
||||
} |
|
||||
|
|
@ -0,0 +1,13 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import android.graphics.RectF |
||||
|
import awais.instagrabber.fragments.imageedit.filters.FiltersHelper |
||||
|
import awais.instagrabber.utils.SerializablePair |
||||
|
import java.util.* |
||||
|
|
||||
|
data class SavedImageEditState(val sessionId: String, val originalPath: String) { |
||||
|
var cropImageMatrixValues: FloatArray? = null // 9 values of matrix |
||||
|
var cropRect: RectF? = null |
||||
|
var appliedTuningFilters: HashMap<FiltersHelper.FilterType, Map<Int, Any>>? = null |
||||
|
var appliedFilter: SerializablePair<FiltersHelper.FilterType, Map<Int, Any>>? = null |
||||
|
} |
@ -1,110 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import androidx.annotation.DrawableRes; |
|
||||
import androidx.annotation.IdRes; |
|
||||
import androidx.annotation.NavigationRes; |
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.util.Objects; |
|
||||
|
|
||||
public class Tab { |
|
||||
private final int iconResId; |
|
||||
private final String title; |
|
||||
private final boolean removable; |
|
||||
|
|
||||
/** |
|
||||
* This is name part of the navigation resource |
|
||||
* eg: @navigation/<b>graphName</b> |
|
||||
*/ |
|
||||
private final String graphName; |
|
||||
|
|
||||
/** |
|
||||
* This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId) |
|
||||
*/ |
|
||||
private final int navigationResId; |
|
||||
|
|
||||
/** |
|
||||
* This is the resource id of the root navigation tag of the navigation resource. |
|
||||
* <p>eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph. |
|
||||
* <p>So this field would equal to the value of R.id.direct_messages_nav_graph |
|
||||
*/ |
|
||||
private final int navigationRootId; |
|
||||
|
|
||||
/** |
|
||||
* This is the start destination of the nav graph |
|
||||
*/ |
|
||||
private final int startDestinationFragmentId; |
|
||||
|
|
||||
public Tab(@DrawableRes final int iconResId, |
|
||||
@NonNull final String title, |
|
||||
final boolean removable, |
|
||||
@NonNull final String graphName, |
|
||||
@NavigationRes final int navigationResId, |
|
||||
@IdRes final int navigationRootId, |
|
||||
@IdRes final int startDestinationFragmentId) { |
|
||||
this.iconResId = iconResId; |
|
||||
this.title = title; |
|
||||
this.removable = removable; |
|
||||
this.graphName = graphName; |
|
||||
this.navigationResId = navigationResId; |
|
||||
this.navigationRootId = navigationRootId; |
|
||||
this.startDestinationFragmentId = startDestinationFragmentId; |
|
||||
} |
|
||||
|
|
||||
public int getIconResId() { |
|
||||
return iconResId; |
|
||||
} |
|
||||
|
|
||||
public String getTitle() { |
|
||||
return title; |
|
||||
} |
|
||||
|
|
||||
public boolean isRemovable() { |
|
||||
return removable; |
|
||||
} |
|
||||
|
|
||||
public String getGraphName() { |
|
||||
return graphName; |
|
||||
} |
|
||||
|
|
||||
public int getNavigationResId() { |
|
||||
return navigationResId; |
|
||||
} |
|
||||
|
|
||||
public int getNavigationRootId() { |
|
||||
return navigationRootId; |
|
||||
} |
|
||||
|
|
||||
public int getStartDestinationFragmentId() { |
|
||||
return startDestinationFragmentId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean equals(final Object o) { |
|
||||
if (this == o) return true; |
|
||||
if (o == null || getClass() != o.getClass()) return false; |
|
||||
final Tab tab = (Tab) o; |
|
||||
return iconResId == tab.iconResId && |
|
||||
removable == tab.removable && |
|
||||
navigationResId == tab.navigationResId && |
|
||||
navigationRootId == tab.navigationRootId && |
|
||||
startDestinationFragmentId == tab.startDestinationFragmentId && |
|
||||
Objects.equals(title, tab.title) && |
|
||||
Objects.equals(graphName, tab.graphName); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public int hashCode() { |
|
||||
return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId, startDestinationFragmentId); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "Tab{" + |
|
||||
"title='" + title + '\'' + |
|
||||
", removable=" + removable + |
|
||||
", graphName='" + graphName + '\'' + |
|
||||
'}'; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,36 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import androidx.annotation.DrawableRes |
||||
|
import androidx.annotation.IdRes |
||||
|
import androidx.annotation.NavigationRes |
||||
|
|
||||
|
data class Tab( |
||||
|
@param:DrawableRes val iconResId: Int, |
||||
|
val title: String, |
||||
|
val isRemovable: Boolean, |
||||
|
|
||||
|
/** |
||||
|
* This is name part of the navigation resource |
||||
|
* eg: @navigation/ **graphName** |
||||
|
*/ |
||||
|
val graphName: String, |
||||
|
|
||||
|
/** |
||||
|
* This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId) |
||||
|
*/ |
||||
|
@param:NavigationRes val navigationResId: Int, |
||||
|
|
||||
|
/** |
||||
|
* This is the resource id of the root navigation tag of the navigation resource. |
||||
|
* |
||||
|
* eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph. |
||||
|
* |
||||
|
* So this field would equal to the value of R.id.direct_messages_nav_graph |
||||
|
*/ |
||||
|
@param:IdRes val navigationRootId: Int, |
||||
|
|
||||
|
/** |
||||
|
* This is the start destination of the nav graph |
||||
|
*/ |
||||
|
@param:IdRes val startDestinationFragmentId: Int, |
||||
|
) |
@ -1,97 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
public class UploadPhotoOptions { |
|
||||
private final String uploadId; |
|
||||
private final String name; |
|
||||
// private final Uri uri; |
|
||||
private final long byteLength; |
|
||||
private final boolean isSideCar; |
|
||||
private final String waterfallId; |
|
||||
|
|
||||
public static class Builder { |
|
||||
private String uploadId; |
|
||||
private String name; |
|
||||
// private Uri uri; |
|
||||
private boolean isSideCar; |
|
||||
private String waterfallId; |
|
||||
private long byteLength; |
|
||||
|
|
||||
private Builder() {} |
|
||||
|
|
||||
public Builder setUploadId(final String uploadId) { |
|
||||
this.uploadId = uploadId; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setName(final String name) { |
|
||||
this.name = name; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
// public Builder setUri(final Uri uri) { |
|
||||
// this.uri = uri; |
|
||||
// return this; |
|
||||
// } |
|
||||
|
|
||||
public Builder setByteLength(final long byteLength) { |
|
||||
this.byteLength = byteLength; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setIsSideCar(final boolean isSideCar) { |
|
||||
this.isSideCar = isSideCar; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setWaterfallId(final String waterfallId) { |
|
||||
this.waterfallId = waterfallId; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public UploadPhotoOptions build() { |
|
||||
return new UploadPhotoOptions(uploadId, name, /*uri,*/ byteLength, isSideCar, waterfallId); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static Builder builder() { |
|
||||
return new Builder(); |
|
||||
} |
|
||||
|
|
||||
public UploadPhotoOptions(final String uploadId, |
|
||||
final String name, |
|
||||
// final Uri uri, |
|
||||
final long byteLength, |
|
||||
final boolean isSideCar, |
|
||||
final String waterfallId) { |
|
||||
this.uploadId = uploadId; |
|
||||
this.name = name; |
|
||||
// this.uri = uri; |
|
||||
this.byteLength = byteLength; |
|
||||
this.isSideCar = isSideCar; |
|
||||
this.waterfallId = waterfallId; |
|
||||
} |
|
||||
|
|
||||
public String getUploadId() { |
|
||||
return uploadId; |
|
||||
} |
|
||||
|
|
||||
public String getName() { |
|
||||
return name; |
|
||||
} |
|
||||
|
|
||||
// public Uri getUri() { |
|
||||
// return uri; |
|
||||
// } |
|
||||
|
|
||||
public long getByteLength() { |
|
||||
return byteLength; |
|
||||
} |
|
||||
|
|
||||
public boolean isSideCar() { |
|
||||
return isSideCar; |
|
||||
} |
|
||||
|
|
||||
public String getWaterfallId() { |
|
||||
return waterfallId; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,9 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
data class UploadPhotoOptions( |
||||
|
val uploadId: String? = null, |
||||
|
val name: String, |
||||
|
val byteLength: Long = 0, |
||||
|
val isSideCar: Boolean = false, |
||||
|
val waterfallId: String? = null, |
||||
|
) |
@ -1,217 +0,0 @@ |
|||||
package awais.instagrabber.models; |
|
||||
|
|
||||
import awais.instagrabber.models.enums.MediaItemType; |
|
||||
|
|
||||
public class UploadVideoOptions { |
|
||||
private final String uploadId; |
|
||||
private final String name; |
|
||||
private final long byteLength; |
|
||||
private final long duration; |
|
||||
private final int width; |
|
||||
private final int height; |
|
||||
private final boolean isSideCar; |
|
||||
private final boolean forAlbum; // Stories |
|
||||
private final boolean isDirect; |
|
||||
private final boolean isDirectVoice; |
|
||||
private final boolean forDirectStory; |
|
||||
private final boolean isIgtvVideo; |
|
||||
private final String waterfallId; |
|
||||
private final long offset; |
|
||||
private final MediaItemType mediaType; |
|
||||
|
|
||||
public static class Builder { |
|
||||
private String uploadId; |
|
||||
private String name; |
|
||||
private long byteLength; |
|
||||
private long duration; |
|
||||
private int width; |
|
||||
private int height; |
|
||||
private boolean isSideCar; |
|
||||
private boolean forAlbum; // Stories |
|
||||
private boolean isDirect; |
|
||||
private boolean isDirectVoice; |
|
||||
private boolean forDirectStory; |
|
||||
private boolean isIgtvVideo; |
|
||||
private String waterfallId; |
|
||||
private long offset; |
|
||||
private MediaItemType mediaType; |
|
||||
|
|
||||
private Builder() {} |
|
||||
|
|
||||
public Builder setUploadId(final String uploadId) { |
|
||||
this.uploadId = uploadId; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setName(final String name) { |
|
||||
this.name = name; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setByteLength(final long byteLength) { |
|
||||
this.byteLength = byteLength; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setDuration(final long duration) { |
|
||||
this.duration = duration; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setWidth(final int width) { |
|
||||
this.width = width; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setHeight(final int height) { |
|
||||
this.height = height; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setIsSideCar(final boolean isSideCar) { |
|
||||
this.isSideCar = isSideCar; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setForAlbum(final boolean forAlbum) { |
|
||||
this.forAlbum = forAlbum; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setIsDirect(final boolean isDirect) { |
|
||||
this.isDirect = isDirect; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setIsDirectVoice(final boolean isDirectVoice) { |
|
||||
this.isDirectVoice = isDirectVoice; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setForDirectStory(final boolean forDirectStory) { |
|
||||
this.forDirectStory = forDirectStory; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setIsIgtvVideo(final boolean isIgtvVideo) { |
|
||||
this.isIgtvVideo = isIgtvVideo; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setWaterfallId(final String waterfallId) { |
|
||||
this.waterfallId = waterfallId; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setOffset(final long offset) { |
|
||||
this.offset = offset; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public Builder setMediaType(final MediaItemType mediaType) { |
|
||||
this.mediaType = mediaType; |
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public UploadVideoOptions build() { |
|
||||
return new UploadVideoOptions(uploadId, name, byteLength, duration, width, height, isSideCar, forAlbum, isDirect, isDirectVoice, |
|
||||
forDirectStory, isIgtvVideo, waterfallId, offset, mediaType); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static Builder builder() { |
|
||||
return new Builder(); |
|
||||
} |
|
||||
|
|
||||
private UploadVideoOptions(final String uploadId, |
|
||||
final String name, |
|
||||
final long byteLength, |
|
||||
final long duration, |
|
||||
final int width, |
|
||||
final int height, |
|
||||
final boolean isSideCar, |
|
||||
final boolean forAlbum, |
|
||||
final boolean isDirect, |
|
||||
final boolean isDirectVoice, |
|
||||
final boolean forDirectStory, |
|
||||
final boolean isIgtvVideo, |
|
||||
final String waterfallId, |
|
||||
final long offset, |
|
||||
final MediaItemType mediaType) { |
|
||||
this.uploadId = uploadId; |
|
||||
this.name = name; |
|
||||
this.byteLength = byteLength; |
|
||||
this.duration = duration; |
|
||||
this.width = width; |
|
||||
this.height = height; |
|
||||
this.isSideCar = isSideCar; |
|
||||
this.forAlbum = forAlbum; |
|
||||
this.isDirect = isDirect; |
|
||||
this.isDirectVoice = isDirectVoice; |
|
||||
this.forDirectStory = forDirectStory; |
|
||||
this.isIgtvVideo = isIgtvVideo; |
|
||||
this.waterfallId = waterfallId; |
|
||||
this.offset = offset; |
|
||||
this.mediaType = mediaType; |
|
||||
} |
|
||||
|
|
||||
public String getUploadId() { |
|
||||
return uploadId; |
|
||||
} |
|
||||
|
|
||||
public String getName() { |
|
||||
return name; |
|
||||
} |
|
||||
|
|
||||
public long getByteLength() { |
|
||||
return byteLength; |
|
||||
} |
|
||||
|
|
||||
public long getDuration() { |
|
||||
return duration; |
|
||||
} |
|
||||
|
|
||||
public int getWidth() { |
|
||||
return width; |
|
||||
} |
|
||||
|
|
||||
public int getHeight() { |
|
||||
return height; |
|
||||
} |
|
||||
|
|
||||
public boolean isSideCar() { |
|
||||
return isSideCar; |
|
||||
} |
|
||||
|
|
||||
public boolean isForAlbum() { |
|
||||
return forAlbum; |
|
||||
} |
|
||||
|
|
||||
public boolean isDirect() { |
|
||||
return isDirect; |
|
||||
} |
|
||||
|
|
||||
public boolean isDirectVoice() { |
|
||||
return isDirectVoice; |
|
||||
} |
|
||||
|
|
||||
public boolean isForDirectStory() { |
|
||||
return forDirectStory; |
|
||||
} |
|
||||
|
|
||||
public boolean isIgtvVideo() { |
|
||||
return isIgtvVideo; |
|
||||
} |
|
||||
|
|
||||
public String getWaterfallId() { |
|
||||
return waterfallId; |
|
||||
} |
|
||||
|
|
||||
public long getOffset() { |
|
||||
return offset; |
|
||||
} |
|
||||
|
|
||||
public MediaItemType getMediaType() { |
|
||||
return mediaType; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,22 @@ |
|||||
|
package awais.instagrabber.models |
||||
|
|
||||
|
import awais.instagrabber.models.enums.MediaItemType |
||||
|
|
||||
|
data class UploadVideoOptions( |
||||
|
val uploadId: String, |
||||
|
val name: String, |
||||
|
val byteLength: Long = 0, |
||||
|
val duration: Long = 0, |
||||
|
val width: Int = 0, |
||||
|
val height: Int = 0, |
||||
|
val isSideCar: Boolean = false, |
||||
|
// Stories |
||||
|
val isForAlbum: Boolean = false, |
||||
|
val isDirect: Boolean = false, |
||||
|
val isDirectVoice: Boolean = false, |
||||
|
val isForDirectStory: Boolean = false, |
||||
|
val isIgtvVideo: Boolean = false, |
||||
|
val waterfallId: String? = null, |
||||
|
val offset: Long = 0, |
||||
|
val mediaType: MediaItemType? = null, |
||||
|
) |
@ -1,106 +0,0 @@ |
|||||
/* |
|
||||
* Copyright (C) 2017 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. |
|
||||
*/ |
|
||||
|
|
||||
package awais.instagrabber.utils; |
|
||||
|
|
||||
import android.os.Handler; |
|
||||
import android.os.Looper; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import com.google.common.util.concurrent.ListeningExecutorService; |
|
||||
import com.google.common.util.concurrent.MoreExecutors; |
|
||||
|
|
||||
import java.util.concurrent.Executor; |
|
||||
import java.util.concurrent.Executors; |
|
||||
|
|
||||
/** |
|
||||
* Global executor pools for the whole application. |
|
||||
* <p> |
|
||||
* Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind |
|
||||
* webservice requests). |
|
||||
*/ |
|
||||
public class AppExecutors { |
|
||||
|
|
||||
private static final int THREAD_COUNT = 3; |
|
||||
private static final Object LOCK = new Object(); |
|
||||
|
|
||||
private static AppExecutors instance; |
|
||||
|
|
||||
private final Executor diskIO; |
|
||||
private final Executor networkIO; |
|
||||
private final MainThreadExecutor mainThread; |
|
||||
private final ListeningExecutorService tasksThread; |
|
||||
|
|
||||
private AppExecutors(Executor diskIO, |
|
||||
Executor networkIO, |
|
||||
MainThreadExecutor mainThread, |
|
||||
ListeningExecutorService tasksThread) { |
|
||||
this.diskIO = diskIO; |
|
||||
this.networkIO = networkIO; |
|
||||
this.mainThread = mainThread; |
|
||||
this.tasksThread = tasksThread; |
|
||||
} |
|
||||
|
|
||||
public static AppExecutors getInstance() { |
|
||||
if (instance == null) { |
|
||||
synchronized (LOCK) { |
|
||||
if (instance == null) { |
|
||||
instance = new AppExecutors(Executors.newSingleThreadExecutor(), |
|
||||
Executors.newFixedThreadPool(THREAD_COUNT), |
|
||||
new MainThreadExecutor(), |
|
||||
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10))); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
return instance; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
public Executor diskIO() { |
|
||||
return diskIO; |
|
||||
} |
|
||||
|
|
||||
public Executor networkIO() { |
|
||||
return networkIO; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
public ListeningExecutorService tasksThread() { |
|
||||
return tasksThread; |
|
||||
} |
|
||||
|
|
||||
public MainThreadExecutor mainThread() { |
|
||||
return mainThread; |
|
||||
} |
|
||||
|
|
||||
public static class MainThreadExecutor implements Executor { |
|
||||
private final Handler mainThreadHandler = new Handler(Looper.getMainLooper()); |
|
||||
|
|
||||
@Override |
|
||||
public void execute(@NonNull Runnable command) { |
|
||||
mainThreadHandler.post(command); |
|
||||
} |
|
||||
|
|
||||
public void execute(final Runnable command, final int delay) { |
|
||||
mainThreadHandler.postDelayed(command, delay); |
|
||||
} |
|
||||
|
|
||||
public void cancel(@NonNull Runnable command) { |
|
||||
mainThreadHandler.removeCallbacks(command); |
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,52 @@ |
|||||
|
/* |
||||
|
* Copyright (C) 2017 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. |
||||
|
*/ |
||||
|
package awais.instagrabber.utils |
||||
|
|
||||
|
import android.os.Handler |
||||
|
import android.os.Looper |
||||
|
import com.google.common.util.concurrent.ListeningExecutorService |
||||
|
import com.google.common.util.concurrent.MoreExecutors |
||||
|
import java.util.concurrent.Executor |
||||
|
import java.util.concurrent.Executors |
||||
|
|
||||
|
/** |
||||
|
* Global executor pools for the whole application. |
||||
|
* |
||||
|
* |
||||
|
* Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind |
||||
|
* webservice requests). |
||||
|
*/ |
||||
|
object AppExecutors { |
||||
|
val diskIO: Executor = Executors.newSingleThreadExecutor() |
||||
|
val networkIO: Executor = Executors.newFixedThreadPool(3) |
||||
|
val mainThread: MainThreadExecutor = MainThreadExecutor() |
||||
|
val tasksThread: ListeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)) |
||||
|
|
||||
|
class MainThreadExecutor : Executor { |
||||
|
private val mainThreadHandler = Handler(Looper.getMainLooper()) |
||||
|
override fun execute(command: Runnable) { |
||||
|
mainThreadHandler.post(command) |
||||
|
} |
||||
|
|
||||
|
fun execute(command: Runnable?, delay: Int) { |
||||
|
mainThreadHandler.postDelayed(command!!, delay.toLong()) |
||||
|
} |
||||
|
|
||||
|
fun cancel(command: Runnable) { |
||||
|
mainThreadHandler.removeCallbacks(command) |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,173 +0,0 @@ |
|||||
package awais.instagrabber.utils; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import com.google.common.collect.ImmutableMap; |
|
||||
|
|
||||
import org.json.JSONObject; |
|
||||
|
|
||||
import java.util.Date; |
|
||||
import java.util.HashMap; |
|
||||
import java.util.Map; |
|
||||
import java.util.UUID; |
|
||||
|
|
||||
import awais.instagrabber.models.UploadPhotoOptions; |
|
||||
import awais.instagrabber.models.UploadVideoOptions; |
|
||||
import awais.instagrabber.models.enums.MediaItemType; |
|
||||
|
|
||||
public final class MediaUploadHelper { |
|
||||
private static final long LOWER = 1000000000L; |
|
||||
private static final long UPPER = 9999999999L; |
|
||||
|
|
||||
private static Map<String, String> createPhotoRuploadParams(final UploadPhotoOptions options) { |
|
||||
final String retryContextString = getRetryContextString(); |
|
||||
final Map<String, String> params = new HashMap<>(); |
|
||||
params.put("retry_context", retryContextString); |
|
||||
params.put("media_type", "1"); |
|
||||
params.put("upload_id", options.getUploadId()); |
|
||||
params.put("xsharing_user_ids", "[]"); |
|
||||
final Map<String, String> imageCompression = new HashMap<>(); |
|
||||
imageCompression.put("lib_name", "moz"); |
|
||||
imageCompression.put("lib_version", "3.1.m"); |
|
||||
imageCompression.put("quality", "80"); |
|
||||
params.put("image_compression", new JSONObject(imageCompression).toString()); |
|
||||
if (options.isSideCar()) { |
|
||||
params.put("is_sidecar", "1"); |
|
||||
} |
|
||||
return params; |
|
||||
} |
|
||||
|
|
||||
private static Map<String, String> createVideoRuploadParams(final UploadVideoOptions options) { |
|
||||
final String retryContextString = getRetryContextString(); |
|
||||
final Map<String, String> ruploadParams = new HashMap<>(); |
|
||||
ruploadParams.put("retry_context", retryContextString); |
|
||||
ruploadParams.put("media_type", "2"); |
|
||||
ruploadParams.put("xsharing_user_ids", "[]"); |
|
||||
ruploadParams.put("upload_id", options.getUploadId()); |
|
||||
ruploadParams.put("upload_media_width", String.valueOf(options.getWidth())); |
|
||||
ruploadParams.put("upload_media_height", String.valueOf(options.getHeight())); |
|
||||
ruploadParams.put("upload_media_duration_ms", String.valueOf(options.getDuration())); |
|
||||
if (options.isSideCar()) { |
|
||||
ruploadParams.put("is_sidecar", "1"); |
|
||||
} |
|
||||
if (options.isForAlbum()) { |
|
||||
ruploadParams.put("for_album", "1"); |
|
||||
} |
|
||||
if (options.isDirect()) { |
|
||||
ruploadParams.put("direct_v2", "1"); |
|
||||
} |
|
||||
if (options.isForDirectStory()) { |
|
||||
ruploadParams.put("for_direct_story", "1"); |
|
||||
ruploadParams.put("content_tags", ""); |
|
||||
} |
|
||||
if (options.isIgtvVideo()) { |
|
||||
ruploadParams.put("is_igtv_video", "1"); |
|
||||
} |
|
||||
if (options.isDirectVoice()) { |
|
||||
ruploadParams.put("is_direct_voice", "1"); |
|
||||
} |
|
||||
return ruploadParams; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static String getRetryContextString() { |
|
||||
final Map<String, Integer> retryContext = new HashMap<>(); |
|
||||
retryContext.put("num_step_auto_retry", 0); |
|
||||
retryContext.put("num_reupload", 0); |
|
||||
retryContext.put("num_step_manual_retry", 0); |
|
||||
return new JSONObject(retryContext).toString(); |
|
||||
} |
|
||||
|
|
||||
public static UploadPhotoOptions createUploadPhotoOptions(final long byteLength) { |
|
||||
final String uploadId = generateUploadId(); |
|
||||
return UploadPhotoOptions.builder() |
|
||||
.setUploadId(uploadId) |
|
||||
.setName(generateName(uploadId)) |
|
||||
.setByteLength(byteLength) |
|
||||
.build(); |
|
||||
} |
|
||||
|
|
||||
public static UploadVideoOptions createUploadDmVideoOptions(final long byteLength, |
|
||||
final long duration, |
|
||||
final int width, |
|
||||
final int height) { |
|
||||
final String uploadId = generateUploadId(); |
|
||||
return UploadVideoOptions.builder() |
|
||||
.setUploadId(uploadId) |
|
||||
.setName(generateName(uploadId)) |
|
||||
.setByteLength(byteLength) |
|
||||
.setDuration(duration) |
|
||||
.setWidth(width) |
|
||||
.setHeight(height) |
|
||||
.setIsDirect(true) |
|
||||
.setMediaType(MediaItemType.MEDIA_TYPE_VIDEO) |
|
||||
.build(); |
|
||||
} |
|
||||
|
|
||||
public static UploadVideoOptions createUploadDmVoiceOptions(final long byteLength, |
|
||||
final long duration) { |
|
||||
final String uploadId = generateUploadId(); |
|
||||
return UploadVideoOptions.builder() |
|
||||
.setUploadId(uploadId) |
|
||||
.setName(generateName(uploadId)) |
|
||||
.setDuration(duration) |
|
||||
.setIsDirectVoice(true) |
|
||||
.setByteLength(byteLength) |
|
||||
.setMediaType(MediaItemType.MEDIA_TYPE_VOICE) |
|
||||
.build(); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static String generateUploadId() { |
|
||||
return String.valueOf(new Date().getTime() / 1000); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static String generateName(final String uploadId) { |
|
||||
final long random = NumberUtils.random(LOWER, UPPER + 1); |
|
||||
return String.format("%s_0_%s", uploadId, random); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static Map<String, String> getUploadPhotoHeaders(@NonNull final UploadPhotoOptions options) { |
|
||||
final String waterfallId = TextUtils.isEmpty(options.getWaterfallId()) ? UUID.randomUUID().toString() : options.getWaterfallId(); |
|
||||
final String contentLength = String.valueOf(options.getByteLength()); |
|
||||
final Map<String, String> headers = new HashMap<>(); |
|
||||
headers.put("X_FB_PHOTO_WATERFALL_ID", waterfallId); |
|
||||
headers.put("X-Entity-Type", "image/jpeg"); |
|
||||
headers.put("Offset", "0"); |
|
||||
headers.put("X-Instagram-Rupload-Params", new JSONObject(createPhotoRuploadParams(options)).toString()); |
|
||||
headers.put("X-Entity-Name", options.getName()); |
|
||||
headers.put("X-Entity-Length", contentLength); |
|
||||
headers.put("Content-Type", "application/octet-stream"); |
|
||||
headers.put("Content-Length", contentLength); |
|
||||
headers.put("Accept-Encoding", "gzip"); |
|
||||
return headers; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static Map<String, String> getUploadVideoHeaders(@NonNull final UploadVideoOptions options) { |
|
||||
final Map<String, String> ruploadParams = createVideoRuploadParams(options); |
|
||||
final String waterfallId = TextUtils.isEmpty(options.getWaterfallId()) ? UUID.randomUUID().toString() : options.getWaterfallId(); |
|
||||
final String contentLength = String.valueOf(options.getByteLength()); |
|
||||
return ImmutableMap.<String, String>builder() |
|
||||
.putAll(getBaseUploadVideoHeaders(ruploadParams)) |
|
||||
.put("X_FB_PHOTO_WATERFALL_ID", waterfallId) |
|
||||
.put("X-Entity-Type", "video/mp4") |
|
||||
.put("Offset", String.valueOf(options.getOffset() > 0 ? options.getOffset() : 0)) |
|
||||
.put("X-Entity-Name", options.getName()) |
|
||||
.put("X-Entity-Length", contentLength) |
|
||||
.put("Content-Type", "application/octet-stream") |
|
||||
.put("Content-Length", contentLength) |
|
||||
.build(); |
|
||||
} |
|
||||
|
|
||||
private static Map<String, String> getBaseUploadVideoHeaders(@NonNull final Map<String, String> ruploadParams) { |
|
||||
return ImmutableMap.of( |
|
||||
"X-IG-Connection-Type", "WIFI", |
|
||||
"X-IG-Capabilities", "3brTvwE=", |
|
||||
"Accept-Encoding", "gzip", |
|
||||
"X-Instagram-Rupload-Params", new JSONObject(ruploadParams).toString() |
|
||||
); |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,154 @@ |
|||||
|
@file:JvmName("MediaUploadHelper") |
||||
|
|
||||
|
package awais.instagrabber.utils |
||||
|
|
||||
|
import awais.instagrabber.models.UploadPhotoOptions |
||||
|
import awais.instagrabber.models.UploadVideoOptions |
||||
|
import awais.instagrabber.models.enums.MediaItemType |
||||
|
import org.json.JSONObject |
||||
|
import java.util.* |
||||
|
|
||||
|
|
||||
|
private const val LOWER = 1000000000L |
||||
|
private const val UPPER = 9999999999L |
||||
|
|
||||
|
private fun createPhotoRuploadParams(options: UploadPhotoOptions): Map<String, String> { |
||||
|
val imageCompression = mapOf( |
||||
|
"lib_name" to "moz", |
||||
|
"lib_version" to "3.1.m", |
||||
|
"quality" to "80", |
||||
|
) |
||||
|
return listOfNotNull( |
||||
|
"retry_context" to retryContextString, |
||||
|
"media_type" to "1", |
||||
|
"upload_id" to (options.uploadId ?: ""), |
||||
|
"xsharing_user_ids" to "[]", |
||||
|
"image_compression" to JSONObject(imageCompression).toString(), |
||||
|
if (options.isSideCar) "is_sidecar" to "1" else null, |
||||
|
).toMap() |
||||
|
} |
||||
|
|
||||
|
private fun createVideoRuploadParams(options: UploadVideoOptions): Map<String, String> { |
||||
|
val retryContextString = retryContextString |
||||
|
return listOfNotNull( |
||||
|
"retry_context" to retryContextString, |
||||
|
"media_type" to "2", |
||||
|
"xsharing_user_ids" to "[]", |
||||
|
"upload_id" to options.uploadId, |
||||
|
"upload_media_width" to options.width.toString(), |
||||
|
"upload_media_height" to options.height.toString(), |
||||
|
"upload_media_duration_ms" to options.duration.toString(), |
||||
|
if (options.isSideCar) "is_sidecar" to "1" else null, |
||||
|
if (options.isForAlbum) "for_album" to "1" else null, |
||||
|
if (options.isDirect) "direct_v2" to "1" else null, |
||||
|
*(if (options.isForDirectStory) arrayOf( |
||||
|
"for_direct_story" to "1", |
||||
|
"content_tags" to "" |
||||
|
) else emptyArray()), |
||||
|
if (options.isIgtvVideo) "is_igtv_video" to "1" else null, |
||||
|
if (options.isDirectVoice) "is_direct_voice" to "1" else null, |
||||
|
).toMap() |
||||
|
} |
||||
|
|
||||
|
val retryContextString: String |
||||
|
get() { |
||||
|
return JSONObject( |
||||
|
mapOf( |
||||
|
"num_step_auto_retry" to 0, |
||||
|
"num_reupload" to 0, |
||||
|
"num_step_manual_retry" to 0, |
||||
|
) |
||||
|
).toString() |
||||
|
} |
||||
|
|
||||
|
fun createUploadPhotoOptions(byteLength: Long): UploadPhotoOptions { |
||||
|
val uploadId = generateUploadId() |
||||
|
return UploadPhotoOptions( |
||||
|
uploadId, |
||||
|
generateName(uploadId), |
||||
|
byteLength, |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
fun createUploadDmVideoOptions( |
||||
|
byteLength: Long, |
||||
|
duration: Long, |
||||
|
width: Int, |
||||
|
height: Int |
||||
|
): UploadVideoOptions { |
||||
|
val uploadId = generateUploadId() |
||||
|
return UploadVideoOptions( |
||||
|
uploadId, |
||||
|
generateName(uploadId), |
||||
|
byteLength, |
||||
|
duration, |
||||
|
width, |
||||
|
height, |
||||
|
true, |
||||
|
mediaType = MediaItemType.MEDIA_TYPE_VIDEO, |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
fun createUploadDmVoiceOptions( |
||||
|
byteLength: Long, |
||||
|
duration: Long |
||||
|
): UploadVideoOptions { |
||||
|
val uploadId = generateUploadId() |
||||
|
return UploadVideoOptions( |
||||
|
uploadId, |
||||
|
generateName(uploadId), |
||||
|
byteLength, |
||||
|
duration, |
||||
|
isDirectVoice = true, |
||||
|
mediaType = MediaItemType.MEDIA_TYPE_VOICE, |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
fun generateUploadId(): String { |
||||
|
return (Date().time / 1000).toString() |
||||
|
} |
||||
|
|
||||
|
fun generateName(uploadId: String): String { |
||||
|
val random = NumberUtils.random(LOWER, UPPER + 1) |
||||
|
return "${uploadId}_0_$random" |
||||
|
} |
||||
|
|
||||
|
fun getUploadPhotoHeaders(options: UploadPhotoOptions): Map<String, String> { |
||||
|
val waterfallId = options.waterfallId ?: UUID.randomUUID().toString() |
||||
|
val contentLength = options.byteLength.toString() |
||||
|
return mapOf( |
||||
|
"X_FB_PHOTO_WATERFALL_ID" to waterfallId, |
||||
|
"X-Entity-Type" to "image/jpeg", |
||||
|
"Offset" to "0", |
||||
|
"X-Instagram-Rupload-Params" to JSONObject(createPhotoRuploadParams(options)).toString(), |
||||
|
"X-Entity-Name" to options.name, |
||||
|
"X-Entity-Length" to contentLength, |
||||
|
"Content-Type" to "application/octet-stream", |
||||
|
"Content-Length" to contentLength, |
||||
|
"Accept-Encoding" to "gzip", |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
fun getUploadVideoHeaders(options: UploadVideoOptions): Map<String, String> { |
||||
|
val ruploadParams = createVideoRuploadParams(options) |
||||
|
val waterfallId = options.waterfallId ?: UUID.randomUUID().toString() |
||||
|
val contentLength = options.byteLength.toString() |
||||
|
return getBaseUploadVideoHeaders(ruploadParams) + mapOf( |
||||
|
"X_FB_PHOTO_WATERFALL_ID" to waterfallId, |
||||
|
"X-Entity-Type" to "video/mp4", |
||||
|
"Offset" to (if (options.offset > 0) options.offset else 0).toString(), |
||||
|
"X-Entity-Name" to options.name, |
||||
|
"X-Entity-Length" to contentLength, |
||||
|
"Content-Type" to "application/octet-stream", |
||||
|
"Content-Length" to contentLength, |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
private fun getBaseUploadVideoHeaders(ruploadParams: Map<String, String>): Map<String, String> { |
||||
|
return mapOf( |
||||
|
"X-IG-Connection-Type" to "WIFI", |
||||
|
"X-IG-Capabilities" to "3brTvwE=", |
||||
|
"Accept-Encoding" to "gzip", |
||||
|
"X-Instagram-Rupload-Params" to JSONObject(ruploadParams).toString() |
||||
|
) |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue