diff --git a/.travis.yml b/.travis.yml index c16bd731..a004be20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,14 @@ jdk: oraclejdk8 sudo: required +before_install: + # Skip build if the commit message contains [skip travis] or [travis skip] + - > + echo "$TRAVIS_COMMIT_MESSAGE" + | grep -E '\[(skip travis|travis skip)\]' + && echo "[skip travis] has been found, exiting." + && exit 0 || true + before_script: - (while sleep 3; do echo "y"; done) | $ANDROID_HOME/tools/bin/sdkmanager "platform-tools" "extras;android;m2repository" "extras;google;m2repository" "build-tools;26.0.0" "platforms;android-26" @@ -27,5 +35,10 @@ after_success: - bash <(curl -s https://codecov.io/bash) notifications: - slack: fasthub:mjJWGD8UpgSgKawKa5OqMNlR - email: false + webhooks: + urls: + - https://discordapp.com/api/webhooks/341508199612153857/_86ddhBkrka3SaPzYJtL2LBH-sKeVI_tSAp0L2h4cPoy2m4CLa4lpqqJu4rjxHs86V0i + on_success: always + on_failure: always + on_start: never + email: false diff --git a/README.md b/README.md index 5f25abef..45cee324 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ We have configured snapshots of FastHub, which can be downloaded from [AppVeyor - Markdown and code highlighting support - Notifications overview and "Mark all as read" - Search users/orgs, repos, issues/prs & code. - - Pinned Repos + - FastHub & GitHub Pinned Repos - Trending - Wiki - **Repositories** @@ -65,6 +65,7 @@ We have configured snapshots of FastHub, which can be downloaded from [AppVeyor - Comment on Commits/Gists - Manage Commit/Gist comments - Create/Delete Gists + - Edit Gist & Gist Files - React to Commit comments with reactions - Comment on line number in Files/Code changes. - **Orgs** @@ -73,6 +74,7 @@ We have configured snapshots of FastHub, which can be downloaded from [AppVeyor - Teams & Teams repos - Repos - **Users** + - GitHub Pinned Repos - Follow/Unfollow users - View user feeds - Contribution graph. @@ -177,7 +179,7 @@ Read the [**contribution guide**](.github/CONTRIBUTING.md) for more detailed inf [Google+](https://plus.google.com/+CookiconsDesign) | [Twitter](https://twitter.com/mcookie) Designer website [Cookicons](https://cookicons.co/). -**OLD FastHub** logo is designed by **Kevin Aguilar**. +**OLD FastHub** logo was designed by **Kevin Aguilar**. [Google+](https://plus.google.com/+KevinAguilarC) | [Twitter](https://twitter.com/kevttob) Designer at [221 Pixels](https://www.221pixels.com/). Laus Deo Semper diff --git a/app/build.gradle b/app/build.gradle index 47712567..a1be537c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,8 +1,9 @@ apply plugin: 'com.android.application' +apply plugin: 'com.apollographql.android' apply plugin: 'kotlin-android' apply plugin: 'com.novoda.build-properties' apply plugin: 'jacoco-android' -apply plugin: 'io.fabric' +if (isProduction) apply plugin: 'io.fabric' buildProperties { notThere { @@ -23,7 +24,7 @@ android { } } compileSdkVersion 26 - buildToolsVersion "26.0.0" + buildToolsVersion "26.0.1" defaultConfig { applicationId "com.fastaccess.github" minSdkVersion 21 @@ -58,7 +59,6 @@ android { } applicationIdSuffix ".debug" versionNameSuffix "-debug" - ext.alwaysUpdateBuildId = false } } @@ -110,13 +110,12 @@ repositories { maven { url "https://clojars.org/repo/" } maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url "https://jitpack.io" } - maven { url 'https://maven.fabric.io/public' } + if (isProduction) maven { url 'https://maven.fabric.io/public' } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation "com.android.support:appcompat-v7:${supportVersion}" - implementation 'com.jaredrummler:android-device-names:1.1.4' implementation "com.android.support:design:${supportVersion}" implementation "com.android.support:cardview-v7:${supportVersion}" implementation "com.android.support:recyclerview-v7:${supportVersion}" @@ -129,10 +128,9 @@ dependencies { implementation "com.squareup.retrofit2:converter-gson:${retrofit}" implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit}" implementation "com.github.bumptech.glide:glide:3.7.0" -// implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation 'cn.gavinliu.android.lib:ShapedImageView:0.8.3' implementation "com.jakewharton:butterknife:${butterKnifeVersion}" - implementation 'it.sephiroth.android.library.bottomnavigation:bottom-navigation:2.0.1-rc1' + implementation 'it.sephiroth.android.library.bottomnavigation:bottom-navigation:2.0.2' implementation 'io.reactivex.rxjava2:rxjava:2.1.0' implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0' @@ -146,26 +144,34 @@ dependencies { implementation 'com.github.nightwhistler:HtmlSpanner:0.4' implementation 'net.sourceforge.htmlcleaner:htmlcleaner:2.2' implementation 'com.github.matthiasrobbers:shortbread:1.0.1' - implementation 'com.atlassian.commonmark:commonmark:0.9.0' + implementation "com.atlassian.commonmark:commonmark:${commonmark}" + implementation "com.atlassian.commonmark:commonmark-ext-autolink:${commonmark}" + implementation "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:${commonmark}" + implementation "com.atlassian.commonmark:commonmark-ext-gfm-tables:${commonmark}" + implementation "com.atlassian.commonmark:commonmark-ext-ins:${commonmark}" + implementation "com.atlassian.commonmark:commonmark-ext-yaml-front-matter:${commonmark}" implementation "com.google.firebase:firebase-messaging:${gms}" - implementation "com.google.android.gms:play-services-ads:${gms}" implementation "com.google.firebase:firebase-database:${gms}" + implementation "com.google.android.gms:play-services-base:${gms}" implementation('com.github.b3er.rxfirebase:firebase-database-kotlin:11.2.0') { transitive = false } implementation('com.github.b3er.rxfirebase:firebase-database:11.2.0') { transitive = false } implementation 'com.firebase:firebase-jobdispatcher:0.7.0' - implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') { transitive = true } + if (isProduction) implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') { transitive = true } implementation "com.github.miguelbcr:RxBillingService:0.0.3" implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" implementation 'org.jsoup:jsoup:1.10.2' implementation "com.evernote:android-state:${state_version}" implementation "petrov.kristiyan:colorpicker-library:1.1.4" + implementation 'com.apollographql.apollo:apollo-rx2-support:0.4.0' + implementation 'com.jaredrummler:android-device-names:1.1.4' + implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:2.1.0' compileOnly "org.projectlombok:lombok:${lombokVersion}" - kapt "io.requery:requery-processor:${requery}" kapt "org.projectlombok:lombok:${lombokVersion}" kapt "com.evernote:android-state-processor:${state_version}" kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}" kapt 'com.github.matthiasrobbers:shortbread-compiler:1.0.1' kapt "org.projectlombok:lombok:${lombokVersion}" + kapt "io.requery:requery-processor:${requery}" // testImplementation "net.grandcentrix.thirtyinch:thirtyinch-test:$thirtyinchVersion" testImplementation "junit:junit:${junitVersion}" testImplementation "org.mockito:mockito-core:${mockitoVersion}" @@ -178,4 +184,5 @@ dependencies { androidTestImplementation "com.android.support.test.espresso:espresso-core:${espresseVersion}" } +apply plugin: 'ManifestClasspath' apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0edb0acf..d222417b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -83,7 +83,8 @@ + android:parentActivityName=".ui.modules.repos.RepoPagerActivity" + android:windowSoftInputMode="stateAlwaysHidden"> @@ -103,7 +104,8 @@ + android:parentActivityName=".ui.modules.repos.RepoPagerActivity" + android:windowSoftInputMode="stateAlwaysHidden"> @@ -115,7 +117,8 @@ + android:label="@string/markdown" + android:windowSoftInputMode="adjustResize"/> + android:parentActivityName=".ui.modules.main.MainActivity" + android:windowSoftInputMode="stateAlwaysHidden"> @@ -170,8 +174,14 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".ui.modules.repos.RepoPagerActivity"/> - - + + + + dataStore; + private ApolloClient apolloClient; @Override public void onCreate() { super.onCreate(); @@ -45,7 +47,7 @@ public class App extends Application { } private void init() { - initFabric(); + FabricProvider.initFabric(this); RxBillingService.register(this); deleteDatabase("database.db"); getDataStore();//init requery before anything. @@ -58,16 +60,6 @@ public class App extends Application { DeviceNameGetter.getInstance().loadDevice(); } - private void initFabric() { - Fabric fabric = new Fabric.Builder(this) - .kits(new Crashlytics.Builder() - .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) - .build()) - .debuggable(BuildConfig.DEBUG) - .build(); - Fabric.with(fabric); - } - private void setupPreference() { PreferenceManager.setDefaultValues(this, R.xml.fasthub_settings, false); PreferenceManager.setDefaultValues(this, R.xml.about_settings, false); @@ -89,4 +81,14 @@ public class App extends Application { } return dataStore; } + + public ApolloClient getApolloClient() { + if (apolloClient == null) { + apolloClient = ApolloClient.builder() + .serverUrl("https://" + (PrefGetter.isEnterprise() ? PrefGetter.getEnterpriseUrl() : "api.github.com") + "/graphql") + .okHttpClient(RestProvider.provideOkHttpClient()) + .build(); + } + return apolloClient; + } } \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/data/dao/AccessTokenModel.java b/app/src/main/java/com/fastaccess/data/dao/AccessTokenModel.java index 1322ebc9..2766fa0e 100644 --- a/app/src/main/java/com/fastaccess/data/dao/AccessTokenModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/AccessTokenModel.java @@ -30,7 +30,7 @@ public class AccessTokenModel implements Parcelable { dest.writeString(this.tokenType); } - protected AccessTokenModel(Parcel in) { + private AccessTokenModel(Parcel in) { this.id = in.readLong(); this.token = in.readString(); this.hashedToken = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/AppLanguageModel.java b/app/src/main/java/com/fastaccess/data/dao/AppLanguageModel.java index 1fbeb5b2..81350448 100644 --- a/app/src/main/java/com/fastaccess/data/dao/AppLanguageModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/AppLanguageModel.java @@ -22,7 +22,7 @@ import lombok.Setter; dest.writeString(this.label); } - protected AppLanguageModel(Parcel in) { + private AppLanguageModel(Parcel in) { this.value = in.readString(); this.label = in.readString(); } diff --git a/app/src/main/java/com/fastaccess/data/dao/AuthModel.java b/app/src/main/java/com/fastaccess/data/dao/AuthModel.java index d347f281..a37d066e 100644 --- a/app/src/main/java/com/fastaccess/data/dao/AuthModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/AuthModel.java @@ -40,7 +40,7 @@ public class AuthModel implements Parcelable { dest.writeString(this.otpCode); } - protected AuthModel(Parcel in) { + private AuthModel(Parcel in) { this.clientId = in.readString(); this.clientSecret = in.readString(); this.redirectUri = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/BranchesModel.java b/app/src/main/java/com/fastaccess/data/dao/BranchesModel.java index 9e2c3a41..77a08db4 100644 --- a/app/src/main/java/com/fastaccess/data/dao/BranchesModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/BranchesModel.java @@ -37,7 +37,7 @@ public class BranchesModel implements Parcelable { dest.writeByte(this.isTag ? (byte) 1 : (byte) 0); } - protected BranchesModel(Parcel in) { + private BranchesModel(Parcel in) { this.name = in.readString(); this.commit = in.readParcelable(Commit.class.getClassLoader()); this.protectedBranch = in.readByte() != 0; diff --git a/app/src/main/java/com/fastaccess/data/dao/CommentRequestModel.java b/app/src/main/java/com/fastaccess/data/dao/CommentRequestModel.java index 26ea4a7b..caf42eed 100644 --- a/app/src/main/java/com/fastaccess/data/dao/CommentRequestModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/CommentRequestModel.java @@ -13,11 +13,11 @@ import lombok.Setter; */ @Getter @Setter public class CommentRequestModel implements Parcelable { - private String body; - @SerializedName("in_reply_to") private Long inReplyTo; - private String path; - private Integer position; - private Integer line; + public String body; + @SerializedName("in_reply_to") public Long inReplyTo; + public String path; + public Integer position; + public Integer line; public CommentRequestModel() {} @@ -44,7 +44,7 @@ import lombok.Setter; dest.writeValue(this.line); } - protected CommentRequestModel(Parcel in) { + private CommentRequestModel(Parcel in) { this.body = in.readString(); this.inReplyTo = (Long) in.readValue(Long.class.getClassLoader()); this.path = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/CommitCountModel.java b/app/src/main/java/com/fastaccess/data/dao/CommitCountModel.java index 22802147..8b74c785 100644 --- a/app/src/main/java/com/fastaccess/data/dao/CommitCountModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/CommitCountModel.java @@ -26,7 +26,7 @@ import lombok.Setter; public CommitCountModel() {} - protected CommitCountModel(Parcel in) { + private CommitCountModel(Parcel in) { this.all = new ArrayList(); in.readList(this.all, Integer.class.getClassLoader()); this.owner = new ArrayList(); diff --git a/app/src/main/java/com/fastaccess/data/dao/CommitFileChanges.java b/app/src/main/java/com/fastaccess/data/dao/CommitFileChanges.java index b297cfba..7a45c30a 100644 --- a/app/src/main/java/com/fastaccess/data/dao/CommitFileChanges.java +++ b/app/src/main/java/com/fastaccess/data/dao/CommitFileChanges.java @@ -23,7 +23,7 @@ import lombok.Setter; public List linesModel; public CommitFileModel commitFileModel; - public CommitFileChanges() {} + private CommitFileChanges() {} public static Observable constructToObservable(@Nullable List files) { if (files == null || files.isEmpty()) return Observable.empty(); @@ -56,7 +56,7 @@ import lombok.Setter; dest.writeParcelable(this.commitFileModel, flags); } - protected CommitFileChanges(Parcel in) { + private CommitFileChanges(Parcel in) { this.linesModel = in.createTypedArrayList(CommitLinesModel.CREATOR); this.commitFileModel = in.readParcelable(CommitFileModel.class.getClassLoader()); } diff --git a/app/src/main/java/com/fastaccess/data/dao/CommitLinesModel.java b/app/src/main/java/com/fastaccess/data/dao/CommitLinesModel.java index 3591c298..9940b56c 100644 --- a/app/src/main/java/com/fastaccess/data/dao/CommitLinesModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/CommitLinesModel.java @@ -100,7 +100,7 @@ import static com.fastaccess.ui.widgets.DiffLineSpan.HUNK_TITLE; dest.writeInt(this.position); } - protected CommitLinesModel(Parcel in) { + private CommitLinesModel(Parcel in) { this.text = in.readString(); this.color = in.readInt(); this.leftLineNo = in.readInt(); diff --git a/app/src/main/java/com/fastaccess/data/dao/CreateGistModel.java b/app/src/main/java/com/fastaccess/data/dao/CreateGistModel.java index 0e930d79..8beb2811 100644 --- a/app/src/main/java/com/fastaccess/data/dao/CreateGistModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/CreateGistModel.java @@ -19,23 +19,23 @@ import lombok.Setter; public class CreateGistModel implements Parcelable { private HashMap files; private String description; - @SerializedName("public") private boolean publicGist; + @SerializedName("public") private Boolean publicGist; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeSerializable(this.files); dest.writeString(this.description); - dest.writeByte(this.publicGist ? (byte) 1 : (byte) 0); + dest.writeValue(this.publicGist); } - @SuppressWarnings({"WeakerAccess", "unchecked"}) protected CreateGistModel(Parcel in) { + @SuppressWarnings("unchecked") private CreateGistModel(Parcel in) { this.files = (HashMap) in.readSerializable(); this.description = in.readString(); - this.publicGist = in.readByte() != 0; + this.publicGist = (Boolean) in.readValue(Boolean.class.getClassLoader()); } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public static final Creator CREATOR = new Creator() { @Override public CreateGistModel createFromParcel(Parcel source) {return new CreateGistModel(source);} @Override public CreateGistModel[] newArray(int size) {return new CreateGistModel[size];} diff --git a/app/src/main/java/com/fastaccess/data/dao/EditReviewCommentModel.java b/app/src/main/java/com/fastaccess/data/dao/EditReviewCommentModel.java index 62be6592..e5dde19b 100644 --- a/app/src/main/java/com/fastaccess/data/dao/EditReviewCommentModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/EditReviewCommentModel.java @@ -14,11 +14,11 @@ import lombok.Setter; @Getter @Setter public class EditReviewCommentModel implements Parcelable { - private int groupPosition; - private int commentPosition; - private String comment; - private ReviewCommentModel commentModel; - @SerializedName("in_reply_to") private long inReplyTo; + public int groupPosition; + public int commentPosition; + public String comment; + public ReviewCommentModel commentModel; + @SerializedName("in_reply_to") public long inReplyTo; public EditReviewCommentModel() {} @@ -33,7 +33,7 @@ import lombok.Setter; dest.writeLong(this.inReplyTo); } - protected EditReviewCommentModel(Parcel in) { + private EditReviewCommentModel(Parcel in) { this.groupPosition = in.readInt(); this.commentPosition = in.readInt(); this.comment = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/FilesListModel.java b/app/src/main/java/com/fastaccess/data/dao/FilesListModel.java index 7e20da76..1ce1106e 100644 --- a/app/src/main/java/com/fastaccess/data/dao/FilesListModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/FilesListModel.java @@ -6,22 +6,24 @@ import android.os.Parcelable; import java.io.Serializable; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; /** * Created by Kosh on 12 Nov 2016, 11:09 AM */ -@Getter @Setter @NoArgsConstructor +@Getter @Setter public class FilesListModel implements Parcelable, Serializable { - private String filename; - private String type; - private String rawUrl; - private long size; - private String content; - private boolean needFetching; - private String language; + public String filename; + public String type; + public String rawUrl; + public Long size; + public String content; + public Boolean needFetching; + public String language; + + public FilesListModel() { + } @Override public int describeContents() { return 0; } @@ -29,9 +31,9 @@ public class FilesListModel implements Parcelable, Serializable { dest.writeString(this.filename); dest.writeString(this.type); dest.writeString(this.rawUrl); - dest.writeLong(this.size); + dest.writeValue(this.size); dest.writeString(this.content); - dest.writeByte(this.needFetching ? (byte) 1 : (byte) 0); + dest.writeValue(this.needFetching); dest.writeString(this.language); } @@ -39,9 +41,9 @@ public class FilesListModel implements Parcelable, Serializable { this.filename = in.readString(); this.type = in.readString(); this.rawUrl = in.readString(); - this.size = in.readLong(); + this.size = (Long) in.readValue(Long.class.getClassLoader()); this.content = in.readString(); - this.needFetching = in.readByte() != 0; + this.needFetching = (Boolean) in.readValue(Boolean.class.getClassLoader()); this.language = in.readString(); } diff --git a/app/src/main/java/com/fastaccess/data/dao/FilterOptionsModel.java b/app/src/main/java/com/fastaccess/data/dao/FilterOptionsModel.java index 83c61180..e74e4145 100644 --- a/app/src/main/java/com/fastaccess/data/dao/FilterOptionsModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/FilterOptionsModel.java @@ -146,7 +146,7 @@ public class FilterOptionsModel implements Parcelable { dest.writeByte(this.isOrg ? (byte) 1 : (byte) 0); } - protected FilterOptionsModel(Parcel in) { + private FilterOptionsModel(Parcel in) { this.type = in.readString(); this.sort = in.readString(); this.sortDirection = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/FragmentPagerAdapterModel.java b/app/src/main/java/com/fastaccess/data/dao/FragmentPagerAdapterModel.java index 335ac726..ee63cad4 100644 --- a/app/src/main/java/com/fastaccess/data/dao/FragmentPagerAdapterModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/FragmentPagerAdapterModel.java @@ -152,8 +152,7 @@ import lombok.Setter; } @NonNull public static List buildForGist(@NonNull Context context, @NonNull Gist gistsModel) { - - return Stream.of(new FragmentPagerAdapterModel(context.getString(R.string.files), GistFilesListFragment.newInstance(gistsModel.getFiles())), + return Stream.of(new FragmentPagerAdapterModel(context.getString(R.string.files), GistFilesListFragment.newInstance(gistsModel.getFilesAsList(), false)), new FragmentPagerAdapterModel(context.getString(R.string.comments), GistCommentsFragment.newInstance(gistsModel.getGistId()))) .collect(Collectors.toList()); } diff --git a/app/src/main/java/com/fastaccess/data/dao/GroupedNotificationModel.java b/app/src/main/java/com/fastaccess/data/dao/GroupedNotificationModel.java index 867a074d..515d3cb1 100644 --- a/app/src/main/java/com/fastaccess/data/dao/GroupedNotificationModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/GroupedNotificationModel.java @@ -33,7 +33,7 @@ import static com.annimon.stream.Collectors.toList; private Notification notification; private Date date; - public GroupedNotificationModel(Repo repo) { + private GroupedNotificationModel(Repo repo) { this.type = HEADER; this.repo = repo; } diff --git a/app/src/main/java/com/fastaccess/data/dao/GroupedReviewModel.java b/app/src/main/java/com/fastaccess/data/dao/GroupedReviewModel.java index 88f83f21..583c89a4 100644 --- a/app/src/main/java/com/fastaccess/data/dao/GroupedReviewModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/GroupedReviewModel.java @@ -6,14 +6,11 @@ import android.os.Parcelable; import java.util.Date; import java.util.List; -import lombok.Getter; -import lombok.Setter; - /** * Created by Kosh on 07 May 2017, 5:08 PM */ -@Getter @Setter public class GroupedReviewModel implements Parcelable { +public class GroupedReviewModel implements Parcelable { private int position; //to group with! private String diffText; @@ -22,9 +19,56 @@ import lombok.Setter; private long id; private List comments; - public GroupedReviewModel() {} + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public String getDiffText() { + return diffText; + } + + public void setDiffText(String diffText) { + this.diffText = diffText; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { @@ -36,7 +80,7 @@ import lombok.Setter; dest.writeTypedList(this.comments); } - protected GroupedReviewModel(Parcel in) { + private GroupedReviewModel(Parcel in) { this.position = in.readInt(); this.diffText = in.readString(); long tmpDate = in.readLong(); diff --git a/app/src/main/java/com/fastaccess/data/dao/ImgurReponseModel.java b/app/src/main/java/com/fastaccess/data/dao/ImgurReponseModel.java index a029a08b..bd8d66e3 100644 --- a/app/src/main/java/com/fastaccess/data/dao/ImgurReponseModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/ImgurReponseModel.java @@ -25,7 +25,7 @@ import lombok.Setter; public ImgurReponseModel() {} - protected ImgurReponseModel(Parcel in) { + private ImgurReponseModel(Parcel in) { this.success = in.readByte() != 0; this.status = in.readInt(); this.data = in.readParcelable(ImgurImage.class.getClassLoader()); @@ -52,7 +52,7 @@ import lombok.Setter; dest.writeString(this.link); } - protected ImgurImage(Parcel in) { + private ImgurImage(Parcel in) { this.title = in.readString(); this.description = in.readString(); this.link = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/IssueEventAdapterModel.java b/app/src/main/java/com/fastaccess/data/dao/IssueEventAdapterModel.java index 70a11037..915df44b 100644 --- a/app/src/main/java/com/fastaccess/data/dao/IssueEventAdapterModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/IssueEventAdapterModel.java @@ -55,7 +55,7 @@ public class IssueEventAdapterModel implements Parcelable { dest.writeParcelable(this.issueModel, flags); } - protected IssueEventAdapterModel(Parcel in) { + private IssueEventAdapterModel(Parcel in) { this.type = in.readInt(); this.issueEvent = in.readParcelable(IssueEvent.class.getClassLoader()); this.issueModel = in.readParcelable(Issue.class.getClassLoader()); diff --git a/app/src/main/java/com/fastaccess/data/dao/IssueRequestModel.java b/app/src/main/java/com/fastaccess/data/dao/IssueRequestModel.java index 8c012533..73a7a805 100644 --- a/app/src/main/java/com/fastaccess/data/dao/IssueRequestModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/IssueRequestModel.java @@ -71,7 +71,7 @@ public class IssueRequestModel implements Parcelable { dest.writeStringList(this.labels); } - protected IssueRequestModel(Parcel in) { + private IssueRequestModel(Parcel in) { int tmpState = in.readInt(); this.state = tmpState == -1 ? null : IssueState.values()[tmpState]; this.title = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/IssuesPageable.java b/app/src/main/java/com/fastaccess/data/dao/IssuesPageable.java new file mode 100644 index 00000000..99e8b365 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/IssuesPageable.java @@ -0,0 +1,53 @@ +package com.fastaccess.data.dao; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.List; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * Created by Kosh on 15 Nov 2016, 7:04 PM + */ + + +@Getter @Setter @NoArgsConstructor +public class IssuesPageable implements Parcelable { + + public int first; + public int next; + public int prev; + public int last; + public int totalCount; + public boolean incompleteResults; + public List items; + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.first); + dest.writeInt(this.next); + dest.writeInt(this.prev); + dest.writeInt(this.last); + dest.writeInt(this.totalCount); + dest.writeByte(this.incompleteResults ? (byte) 1 : (byte) 0); + } + + @SuppressWarnings("WeakerAccess") protected IssuesPageable(Parcel in) { + this.first = in.readInt(); + this.next = in.readInt(); + this.prev = in.readInt(); + this.last = in.readInt(); + this.totalCount = in.readInt(); + this.incompleteResults = in.readByte() != 0; + } + + public static final Creator CREATOR = new Creator() { + @Override public IssuesPageable createFromParcel(Parcel source) {return new IssuesPageable(source);} + + @Override public IssuesPageable[] newArray(int size) {return new IssuesPageable[size];} + }; +} diff --git a/app/src/main/java/com/fastaccess/data/dao/LanguageColorModel.java b/app/src/main/java/com/fastaccess/data/dao/LanguageColorModel.java index 15c89e64..2f40fc9a 100644 --- a/app/src/main/java/com/fastaccess/data/dao/LanguageColorModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/LanguageColorModel.java @@ -24,7 +24,7 @@ import lombok.ToString; public LanguageColorModel() {} - protected LanguageColorModel(Parcel in) { + private LanguageColorModel(Parcel in) { this.color = in.readString(); this.url = in.readString(); } diff --git a/app/src/main/java/com/fastaccess/data/dao/PostReactionModel.java b/app/src/main/java/com/fastaccess/data/dao/PostReactionModel.java index 0a513f9a..46f428e8 100644 --- a/app/src/main/java/com/fastaccess/data/dao/PostReactionModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/PostReactionModel.java @@ -20,7 +20,7 @@ import lombok.Setter; @Override public void writeToParcel(Parcel dest, int flags) {dest.writeString(this.content);} - protected PostReactionModel(Parcel in) {this.content = in.readString();} + private PostReactionModel(Parcel in) {this.content = in.readString();} public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public PostReactionModel createFromParcel(Parcel source) {return new PostReactionModel(source);} diff --git a/app/src/main/java/com/fastaccess/data/dao/PullRequestAdapterModel.java b/app/src/main/java/com/fastaccess/data/dao/PullRequestAdapterModel.java index adb10254..92d2451f 100644 --- a/app/src/main/java/com/fastaccess/data/dao/PullRequestAdapterModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/PullRequestAdapterModel.java @@ -55,7 +55,7 @@ public class PullRequestAdapterModel implements Parcelable { dest.writeParcelable(this.pullRequest, flags); } - protected PullRequestAdapterModel(Parcel in) { + private PullRequestAdapterModel(Parcel in) { this.type = in.readInt(); this.issueEvent = in.readParcelable(IssueEvent.class.getClassLoader()); this.pullRequest = in.readParcelable(PullRequest.class.getClassLoader()); diff --git a/app/src/main/java/com/fastaccess/data/dao/PullRequestStatusModel.java b/app/src/main/java/com/fastaccess/data/dao/PullRequestStatusModel.java index bf37f119..b8e0b566 100644 --- a/app/src/main/java/com/fastaccess/data/dao/PullRequestStatusModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/PullRequestStatusModel.java @@ -41,7 +41,7 @@ import lombok.Setter; dest.writeLong(this.createdAt != null ? this.createdAt.getTime() : -1); } - protected PullRequestStatusModel(Parcel in) { + private PullRequestStatusModel(Parcel in) { int tmpState = in.readInt(); this.state = tmpState == -1 ? null : StatusStateType.values()[tmpState]; this.sha = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/ReactionsModel.java b/app/src/main/java/com/fastaccess/data/dao/ReactionsModel.java index 00e9f1f7..26793c22 100644 --- a/app/src/main/java/com/fastaccess/data/dao/ReactionsModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/ReactionsModel.java @@ -2,12 +2,18 @@ package com.fastaccess.data.dao; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; import com.fastaccess.data.dao.model.User; import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; +import java.util.List; + import lombok.Getter; +import lombok.NonNull; import lombok.Setter; +import pr.PullRequestTimelineQuery; /** * Created by Kosh on 28 Mar 2017, 9:15 PM @@ -15,18 +21,19 @@ import lombok.Setter; @Getter @Setter public class ReactionsModel implements Parcelable { - private long id; - private String url; - private int total_count; - @SerializedName("+1") private int plusOne; - @SerializedName("-1") private int minusOne; - private int laugh; - private int hooray; - private int confused; - private int heart; - private String content; - private User user; - private boolean isCallingApi; + public long id; + public String url; + public int total_count; + @SerializedName("+1") public int plusOne; + @SerializedName("-1") public int minusOne; + public int laugh; + public int hooray; + public int confused; + public int heart; + public String content; + public User user; + public boolean viewerHasReacted; + public boolean isCallingApi; public ReactionsModel() {} @@ -81,4 +88,46 @@ import lombok.Setter; @Override public ReactionsModel[] newArray(int size) {return new ReactionsModel[size];} }; + + @NonNull public static List getReactionGroup(@Nullable List reactions) { + List models = new ArrayList<>(); + if (reactions != null && !reactions.isEmpty()) { + for (PullRequestTimelineQuery.ReactionGroup reaction : reactions) { + ReactionsModel model = new ReactionsModel(); + model.setContent(reaction.content().name()); + model.setViewerHasReacted(reaction.viewerHasReacted()); + model.setTotal_count(reaction.users().totalCount()); + models.add(model); + } + } + return models; + } + + @NonNull public static List getReaction(@Nullable List reactions) { + List models = new ArrayList<>(); + if (reactions != null && !reactions.isEmpty()) { + for (PullRequestTimelineQuery.ReactionGroup1 reaction : reactions) { + ReactionsModel model = new ReactionsModel(); + model.setContent(reaction.content().name()); + model.setViewerHasReacted(reaction.viewerHasReacted()); + model.setTotal_count(reaction.users().totalCount()); + models.add(model); + } + } + return models; + } + + @NonNull public static List getReaction2(@Nullable List reactions) { + List models = new ArrayList<>(); + if (reactions != null && !reactions.isEmpty()) { + for (PullRequestTimelineQuery.ReactionGroup2 reaction : reactions) { + ReactionsModel model = new ReactionsModel(); + model.setContent(reaction.content().name()); + model.setViewerHasReacted(reaction.viewerHasReacted()); + model.setTotal_count(reaction.users().totalCount()); + models.add(model); + } + } + return models; + } } diff --git a/app/src/main/java/com/fastaccess/data/dao/ReviewCommentModel.java b/app/src/main/java/com/fastaccess/data/dao/ReviewCommentModel.java index 9c253401..fbfb288e 100644 --- a/app/src/main/java/com/fastaccess/data/dao/ReviewCommentModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/ReviewCommentModel.java @@ -7,14 +7,11 @@ import com.fastaccess.data.dao.model.User; import java.util.Date; -import lombok.Getter; -import lombok.Setter; - /** * Created by Kosh on 04 May 2017, 7:10 PM */ -@Getter @Setter public class ReviewCommentModel implements Parcelable { + public class ReviewCommentModel implements Parcelable { private long id; private String url; @@ -36,6 +33,147 @@ import lombok.Setter; public ReviewCommentModel() {} + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public long getPullRequestReviewId() { + return pullRequestReviewId; + } + + public void setPullRequestReviewId(long pullRequestReviewId) { + this.pullRequestReviewId = pullRequestReviewId; + } + + public String getDiffHunk() { + return diffHunk; + } + + public void setDiffHunk(String diffHunk) { + this.diffHunk = diffHunk; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public int getOriginalPosition() { + return originalPosition; + } + + public void setOriginalPosition(int originalPosition) { + this.originalPosition = originalPosition; + } + + public String getCommitId() { + return commitId; + } + + public void setCommitId(String commitId) { + this.commitId = commitId; + } + + public String getOriginalCommitId() { + return originalCommitId; + } + + public void setOriginalCommitId(String originalCommitId) { + this.originalCommitId = originalCommitId; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public String getBodyHtml() { + return bodyHtml; + } + + public void setBodyHtml(String bodyHtml) { + this.bodyHtml = bodyHtml; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getHtmlUrl() { + return htmlUrl; + } + + public void setHtmlUrl(String htmlUrl) { + this.htmlUrl = htmlUrl; + } + + public String getPullRequestUrl() { + return pullRequestUrl; + } + + public void setPullRequestUrl(String pullRequestUrl) { + this.pullRequestUrl = pullRequestUrl; + } + + public ReactionsModel getReactions() { + return reactions; + } + + public void setReactions(ReactionsModel reactions) { + this.reactions = reactions; + } + + @Override public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ReviewCommentModel that = (ReviewCommentModel) o; + + return id == that.id; + } + + @Override public int hashCode() { + return (int) (id ^ (id >>> 32)); + } + @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { @@ -85,4 +223,12 @@ import lombok.Setter; @Override public ReviewCommentModel[] newArray(int size) {return new ReviewCommentModel[size];} }; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } } diff --git a/app/src/main/java/com/fastaccess/data/dao/ReviewModel.java b/app/src/main/java/com/fastaccess/data/dao/ReviewModel.java index 5c0392e1..9e6d9421 100644 --- a/app/src/main/java/com/fastaccess/data/dao/ReviewModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/ReviewModel.java @@ -4,59 +4,67 @@ import android.os.Parcel; import android.os.Parcelable; import com.fastaccess.data.dao.model.User; -import com.fastaccess.data.dao.types.ReviewStateType; -import com.google.gson.annotations.SerializedName; import java.util.Date; import java.util.List; -import lombok.Getter; -import lombok.Setter; - /** * Created by Kosh on 10 Apr 2017, 4:26 PM */ -@Getter @Setter public class ReviewModel implements Parcelable { +public class ReviewModel implements Parcelable { private long id; private User user; - @SerializedName("body_html") private String body; - private ReviewStateType state; + private String bodyHtml; + private String state; private Date submittedAt; private String commitId; private String diffText; private List comments; private ReactionsModel reactions; + private String bodyText; public ReviewModel() {} + @Override public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ReviewModel that = (ReviewModel) o; + return id == that.id; + } + + @Override public int hashCode() { + return (int) (id ^ (id >>> 32)); + } + @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(this.id); dest.writeParcelable(this.user, flags); - dest.writeString(this.body); - dest.writeInt(this.state == null ? -1 : this.state.ordinal()); + dest.writeString(this.bodyHtml); + dest.writeString(this.state); dest.writeLong(this.submittedAt != null ? this.submittedAt.getTime() : -1); dest.writeString(this.commitId); dest.writeString(this.diffText); dest.writeTypedList(this.comments); dest.writeParcelable(this.reactions, flags); + dest.writeString(this.bodyText); } protected ReviewModel(Parcel in) { this.id = in.readLong(); this.user = in.readParcelable(User.class.getClassLoader()); - this.body = in.readString(); - int tmpState = in.readInt(); - this.state = tmpState == -1 ? null : ReviewStateType.values()[tmpState]; + this.bodyHtml = in.readString(); + this.state = in.readString(); long tmpSubmittedAt = in.readLong(); this.submittedAt = tmpSubmittedAt == -1 ? null : new Date(tmpSubmittedAt); this.commitId = in.readString(); this.diffText = in.readString(); this.comments = in.createTypedArrayList(ReviewCommentModel.CREATOR); this.reactions = in.readParcelable(ReactionsModel.class.getClassLoader()); + this.bodyText = in.readString(); } public static final Creator CREATOR = new Creator() { @@ -64,4 +72,84 @@ import lombok.Setter; @Override public ReviewModel[] newArray(int size) {return new ReviewModel[size];} }; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public String getBodyHtml() { + return bodyHtml; + } + + public void setBodyHtml(String bodyHtml) { + this.bodyHtml = bodyHtml; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Date getSubmittedAt() { + return submittedAt; + } + + public void setSubmittedAt(Date submittedAt) { + this.submittedAt = submittedAt; + } + + public String getCommitId() { + return commitId; + } + + public void setCommitId(String commitId) { + this.commitId = commitId; + } + + public String getDiffText() { + return diffText; + } + + public void setDiffText(String diffText) { + this.diffText = diffText; + } + + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + + public ReactionsModel getReactions() { + return reactions; + } + + public void setReactions(ReactionsModel reactions) { + this.reactions = reactions; + } + + public String getBodyText() { + return bodyText; + } + + public void setBodyText(String bodyText) { + this.bodyText = bodyText; + } } diff --git a/app/src/main/java/com/fastaccess/data/dao/ReviewRequestModel.java b/app/src/main/java/com/fastaccess/data/dao/ReviewRequestModel.java index 7cfcc89d..df40f83c 100644 --- a/app/src/main/java/com/fastaccess/data/dao/ReviewRequestModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/ReviewRequestModel.java @@ -27,7 +27,7 @@ import lombok.Setter; dest.writeTypedList(this.comments); } - protected ReviewRequestModel(Parcel in) { + private ReviewRequestModel(Parcel in) { this.commitId = in.readString(); this.body = in.readString(); this.event = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/SlackInvitePostModel.java b/app/src/main/java/com/fastaccess/data/dao/SlackInvitePostModel.java index e7ca64c6..ee147436 100644 --- a/app/src/main/java/com/fastaccess/data/dao/SlackInvitePostModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/SlackInvitePostModel.java @@ -25,7 +25,7 @@ import lombok.Setter; public SlackInvitePostModel() {} - protected SlackInvitePostModel(Parcel in) { + private SlackInvitePostModel(Parcel in) { this.email = in.readString(); this.first_name = in.readString(); this.last_name = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/SlackResponseModel.java b/app/src/main/java/com/fastaccess/data/dao/SlackResponseModel.java index 72b7b08f..d30da669 100644 --- a/app/src/main/java/com/fastaccess/data/dao/SlackResponseModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/SlackResponseModel.java @@ -23,7 +23,7 @@ import lombok.Setter; public SlackResponseModel() {} - protected SlackResponseModel(Parcel in) { + private SlackResponseModel(Parcel in) { this.ok = in.readByte() != 0; this.error = in.readString(); } diff --git a/app/src/main/java/com/fastaccess/data/dao/StatusesModel.java b/app/src/main/java/com/fastaccess/data/dao/StatusesModel.java index 29c32fc4..adcda4e0 100644 --- a/app/src/main/java/com/fastaccess/data/dao/StatusesModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/StatusesModel.java @@ -39,7 +39,7 @@ import lombok.Setter; dest.writeLong(this.updatedAt != null ? this.updatedAt.getTime() : -1); } - protected StatusesModel(Parcel in) { + private StatusesModel(Parcel in) { this.url = in.readString(); this.id = in.readInt(); int tmpState = in.readInt(); diff --git a/app/src/main/java/com/fastaccess/data/dao/TimelineModel.java b/app/src/main/java/com/fastaccess/data/dao/TimelineModel.java index 5cbabdc8..9dc51593 100644 --- a/app/src/main/java/com/fastaccess/data/dao/TimelineModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/TimelineModel.java @@ -2,249 +2,104 @@ package com.fastaccess.data.dao; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.annimon.stream.Collectors; -import com.annimon.stream.Stream; import com.fastaccess.data.dao.model.Comment; import com.fastaccess.data.dao.model.Issue; -import com.fastaccess.data.dao.model.IssueEvent; import com.fastaccess.data.dao.model.PullRequest; +import com.fastaccess.data.dao.timeline.GenericEvent; +import com.fastaccess.data.dao.timeline.PullRequestCommitModel; import com.fastaccess.data.dao.types.IssueEventType; -import com.fastaccess.data.dao.types.ReviewStateType; -import com.fastaccess.helper.InputHelper; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; +import io.reactivex.Observable; import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.NonNull; import lombok.Setter; -import static com.annimon.stream.Collectors.toList; - /** * Created by Kosh on 30 Mar 2017, 9:03 PM */ -@Getter @Setter @NoArgsConstructor public class TimelineModel implements Parcelable { - public static final int HEADER = 0; - public static final int STATUS = 1; - public static final int REVIEW = 2; - public static final int GROUPED_REVIEW = 3; - public static final int EVENT = 4; - public static final int COMMENT = 5; +@Getter @Setter public class TimelineModel implements Parcelable { + public static final int HEADER = 1; + public static final int EVENT = 2; + public static final int COMMENT = 3; + public static final int REVIEW = 4; + public static final int GROUP = 5; + public static final int COMMIT_COMMENTS = 6; + public static final int STATUS = 7; - private int type; - private Issue issue; + private IssueEventType event; private Comment comment; - private IssueEvent event; - private PullRequest pullRequest; + private GenericEvent genericEvent; private PullRequestStatusModel status; + private Issue issue; + private PullRequest pullRequest; private ReviewModel review; - private GroupedReviewModel groupedReview; - private ReviewCommentModel reviewComment; - private Date sortedDate; + private GroupedReviewModel groupedReviewModel; + private PullRequestCommitModel commit; - private TimelineModel(Issue issue) { - this.type = HEADER; + public TimelineModel(Issue issue) { this.issue = issue; - this.sortedDate = issue.getCreatedAt(); } - private TimelineModel(PullRequest pullRequest) { - this.type = HEADER; + public TimelineModel(PullRequest pullRequest) { this.pullRequest = pullRequest; - this.sortedDate = pullRequest.getCreatedAt(); } - private TimelineModel(Comment comment) { - this.type = COMMENT; + public TimelineModel(Comment comment) { this.comment = comment; - this.sortedDate = comment.getCreatedAt() == null ? new Date() : comment.getCreatedAt(); + this.event = IssueEventType.commented; } - private TimelineModel(IssueEvent event) { - this.type = EVENT; - this.event = event; - this.sortedDate = event.getCreatedAt(); + public TimelineModel(PullRequestStatusModel statusModel) { + this.status = statusModel; } - private TimelineModel(PullRequestStatusModel status) { - this.type = STATUS; - this.status = status; - this.sortedDate = status.getCreatedAt(); + public TimelineModel() {} + + public int getType() { + if (getEvent() != null) { + switch (getEvent()) { + case commented: + return COMMENT; + case reviewed: + case changes_requested: + return REVIEW; + case GROUPED: + return GROUP; + case commit_commented: + return COMMIT_COMMENTS; + default: + return EVENT; + } + } else { + if (issue != null || pullRequest != null) return HEADER; + else if (status != null) return STATUS; + return 0; + } } - private TimelineModel(ReviewModel review) { - this.type = REVIEW; - this.review = review; - this.sortedDate = review.getSubmittedAt(); - } - - private TimelineModel(GroupedReviewModel groupedReview) { - this.type = GROUPED_REVIEW; - this.groupedReview = groupedReview; - this.sortedDate = groupedReview.getDate(); - } - - @NonNull public static TimelineModel constructHeader(@NonNull Issue issue) { + public static TimelineModel constructHeader(Issue issue) { return new TimelineModel(issue); } - @NonNull public static TimelineModel constructHeader(@NonNull PullRequest pullRequest) { + public static TimelineModel constructHeader(PullRequest pullRequest) { return new TimelineModel(pullRequest); } - @NonNull public static TimelineModel constructComment(@NonNull Comment comment) { + public static TimelineModel constructComment(Comment comment) { return new TimelineModel(comment); } - @NonNull public static List construct(@Nullable List commentList) { - ArrayList list = new ArrayList<>(); - if (commentList != null && !commentList.isEmpty()) { - list.addAll(Stream.of(commentList) - .map(TimelineModel::new) - .collect(Collectors.toList())); - } - return list; - } - - @NonNull public static List construct(@Nullable List commentList, @Nullable List eventList) { - ArrayList list = new ArrayList<>(); - if (commentList != null && !commentList.isEmpty()) { - list.addAll(Stream.of(commentList) - .map(TimelineModel::new) - .collect(Collectors.toList())); - } - if (eventList != null && !eventList.isEmpty()) { - list.addAll(constructLabels(eventList)); - } - - return Stream.of(list).sorted((o1, o2) -> { - if (o1.getEvent() != null && o2.getComment() != null) { - return o1.getEvent().getCreatedAt().compareTo(o2.getComment().getCreatedAt()); - } else if (o1.getComment() != null && o2.getEvent() != null) { - return o1.getComment().getCreatedAt().compareTo(o2.getEvent().getCreatedAt()); - } else { - return Integer.valueOf(o1.getType()).compareTo(o2.getType()); - } - }).collect(Collectors.toList()); - } - - @NonNull public static List construct(@Nullable List commentList, @Nullable List eventList, - @Nullable PullRequestStatusModel status, @Nullable List reviews, - @Nullable List reviewComments) { - ArrayList list = new ArrayList<>(); - if (status != null) { - list.add(new TimelineModel(status)); - } - if (reviews != null && !reviews.isEmpty()) { - list.addAll(constructReviews(reviews, reviewComments)); - } - if (commentList != null && !commentList.isEmpty()) { - list.addAll(Stream.of(commentList) - .map(TimelineModel::new) - .collect(Collectors.toList())); - } - if (eventList != null && !eventList.isEmpty()) { - list.addAll(constructLabels(eventList)); - } - - return Stream.of(list).sortBy(model -> { - if (model.getSortedDate() != null) { - return model.getSortedDate().getTime(); - } else { - return (long) model.getType(); - } - }).collect(Collectors.toList()); - } - - @NonNull private static List constructLabels(@NonNull List eventList) { - List models = new ArrayList<>(); - Map> issueEventMap = Stream.of(eventList) - .filter(value -> value.getEvent() != null && value.getEvent() != IssueEventType.subscribed && - value.getEvent() != IssueEventType.unsubscribed && value.getEvent() != IssueEventType.mentioned) - .collect(Collectors.groupingBy(issueEvent -> { - if (issueEvent.getAssigner() != null && issueEvent.getAssignee() != null) { - return issueEvent.getAssigner().getLogin(); - } - return issueEvent.getActor().getLogin(); - })); - if (issueEventMap != null && !issueEventMap.isEmpty()) { - for (Map.Entry> stringListEntry : issueEventMap.entrySet()) { - List labelModels = new ArrayList<>(); - List events = stringListEntry.getValue(); - IssueEvent toAdd = null; - for (IssueEvent event : events) { - if (event.getEvent() == IssueEventType.labeled || event.getEvent() == IssueEventType.unlabeled) { - if (toAdd == null) { - toAdd = event; - } - long time = toAdd.getCreatedAt().after(event.getCreatedAt()) ? (toAdd.getCreatedAt().getTime() - event - .getCreatedAt().getTime()) : (event.getCreatedAt().getTime() - toAdd.getCreatedAt().getTime()); - if (TimeUnit.MINUTES.toMinutes(time) <= 2 && toAdd.getEvent() == event.getEvent()) { - labelModels.add(event.getLabel()); - } else { - models.add(new TimelineModel(event)); - } - } else { - models.add(new TimelineModel(event)); - } - } - if (toAdd != null) { - toAdd.setLabels(labelModels); - models.add(new TimelineModel(toAdd)); - } - } - } - return Stream.of(models) - .sortBy(TimelineModel::getSortedDate) - .toList(); - } - - @NonNull private static List constructReviews - (@NonNull List reviews, @Nullable List comments) { - List models = new ArrayList<>(); - if (comments == null || comments.isEmpty()) { - models.addAll(Stream.of(reviews) - .map(TimelineModel::new) - .collect(Collectors.toList())); - } else { // this is how bad github API is. - Map> mappedComments = Stream.of(comments) - .collect(Collectors.groupingBy(ReviewCommentModel::getOriginalPosition, LinkedHashMap::new, - Collectors.mapping(o -> o, toList()))); - for (Map.Entry> entry : mappedComments.entrySet()) { - List reviewCommentModels = entry.getValue(); - GroupedReviewModel groupedReviewModel = new GroupedReviewModel(); - if (!reviewCommentModels.isEmpty()) { - ReviewCommentModel reviewCommentModel = reviewCommentModels.get(0); - groupedReviewModel.setPath(reviewCommentModel.getPath()); - groupedReviewModel.setDiffText(reviewCommentModel.getDiffHunk()); - groupedReviewModel.setDate(reviewCommentModel.getCreatedAt()); - groupedReviewModel.setPosition(reviewCommentModel.getOriginalPosition()); - groupedReviewModel.setId(reviewCommentModel.getId()); - } - for (ReviewCommentModel reviewCommentModel : reviewCommentModels) { - if (reviewCommentModel.getCreatedAt() != null) { - groupedReviewModel.setDate(reviewCommentModel.getCreatedAt()); - break; - } - } - groupedReviewModel.setComments(reviewCommentModels); - models.add(new TimelineModel(groupedReviewModel)); - } - models.addAll(Stream.of(reviews) - .filter(reviewModel -> !InputHelper.isEmpty(reviewModel.getBody()) || reviewModel.getState() == ReviewStateType.APPROVED) - .map(TimelineModel::new) - .collect(Collectors.toList())); - } - return models; + @NonNull public static Observable> construct(@Nullable List comments) { + if (comments == null || comments.isEmpty()) return Observable.empty(); + return Observable.fromIterable(comments) + .map(TimelineModel::new) + .toList() + .toObservable(); } @Override public boolean equals(Object o) { @@ -258,33 +113,104 @@ import static com.annimon.stream.Collectors.toList; return comment != null ? (int) comment.getId() : 0; } + + public IssueEventType getEvent() { + return event; + } + + public void setEvent(IssueEventType event) { + this.event = event; + } + + public Comment getComment() { + return comment; + } + + public void setComment(Comment comment) { + this.comment = comment; + } + + public GenericEvent getGenericEvent() { + return genericEvent; + } + + public void setGenericEvent(GenericEvent genericEvent) { + this.genericEvent = genericEvent; + } + + public PullRequestStatusModel getStatus() { + return status; + } + + public void setStatus(PullRequestStatusModel status) { + this.status = status; + } + + public Issue getIssue() { + return issue; + } + + public void setIssue(Issue issue) { + this.issue = issue; + } + + public PullRequest getPullRequest() { + return pullRequest; + } + + public void setPullRequest(PullRequest pullRequest) { + this.pullRequest = pullRequest; + } + + public ReviewModel getReview() { + return review; + } + + public void setReview(ReviewModel review) { + this.review = review; + } + + public GroupedReviewModel getGroupedReviewModel() { + return groupedReviewModel; + } + + public void setGroupedReviewModel(GroupedReviewModel groupedReviewModel) { + this.groupedReviewModel = groupedReviewModel; + } + + public PullRequestCommitModel getCommit() { + return commit; + } + + public void setCommit(PullRequestCommitModel commit) { + this.commit = commit; + } + @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(this.type); - dest.writeParcelable(this.issue, flags); + dest.writeInt(this.event == null ? -1 : this.event.ordinal()); dest.writeParcelable(this.comment, flags); - dest.writeParcelable(this.event, flags); - dest.writeParcelable(this.pullRequest, flags); + dest.writeParcelable(this.genericEvent, flags); dest.writeParcelable(this.status, flags); + dest.writeParcelable(this.issue, flags); + dest.writeParcelable(this.pullRequest, flags); dest.writeParcelable(this.review, flags); - dest.writeParcelable(this.groupedReview, flags); - dest.writeParcelable(this.reviewComment, flags); - dest.writeLong(this.sortedDate != null ? this.sortedDate.getTime() : -1); + dest.writeParcelable(this.groupedReviewModel, flags); + dest.writeParcelable(this.commit, flags); } protected TimelineModel(Parcel in) { - this.type = in.readInt(); - this.issue = in.readParcelable(Issue.class.getClassLoader()); + int tmpEvent = in.readInt(); + this.event = tmpEvent == -1 ? null : IssueEventType.values()[tmpEvent]; this.comment = in.readParcelable(Comment.class.getClassLoader()); - this.event = in.readParcelable(IssueEvent.class.getClassLoader()); - this.pullRequest = in.readParcelable(PullRequest.class.getClassLoader()); + this.genericEvent = in.readParcelable(GenericEvent.class.getClassLoader()); this.status = in.readParcelable(PullRequestStatusModel.class.getClassLoader()); + this.issue = in.readParcelable(Issue.class.getClassLoader()); + this.pullRequest = in.readParcelable(PullRequest.class.getClassLoader()); this.review = in.readParcelable(ReviewModel.class.getClassLoader()); - this.groupedReview = in.readParcelable(GroupedReviewModel.class.getClassLoader()); - this.reviewComment = in.readParcelable(ReviewCommentModel.class.getClassLoader()); - long tmpSortedDate = in.readLong(); - this.sortedDate = tmpSortedDate == -1 ? null : new Date(tmpSortedDate); + this.groupedReviewModel = in.readParcelable(GroupedReviewModel.class.getClassLoader()); + this.commit = in.readParcelable(PullRequestCommitModel.class.getClassLoader()); } public static final Creator CREATOR = new Creator() { diff --git a/app/src/main/java/com/fastaccess/data/dao/WikiModel.java b/app/src/main/java/com/fastaccess/data/dao/WikiModel.java index d84b543c..02c85ead 100644 --- a/app/src/main/java/com/fastaccess/data/dao/WikiModel.java +++ b/app/src/main/java/com/fastaccess/data/dao/WikiModel.java @@ -32,7 +32,7 @@ import lombok.Setter; dest.writeString(this.htmlUrl); } - protected WikiModel(Parcel in) { + private WikiModel(Parcel in) { this.pageName = in.readString(); this.title = in.readString(); this.summary = in.readString(); diff --git a/app/src/main/java/com/fastaccess/data/dao/model/AbstractGist.java b/app/src/main/java/com/fastaccess/data/dao/model/AbstractGist.java index e90834e3..6177812a 100644 --- a/app/src/main/java/com/fastaccess/data/dao/model/AbstractGist.java +++ b/app/src/main/java/com/fastaccess/data/dao/model/AbstractGist.java @@ -4,6 +4,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; +import com.annimon.stream.Collectors; import com.annimon.stream.LongStream; import com.annimon.stream.Stream; import com.fastaccess.App; @@ -19,6 +20,7 @@ import com.google.gson.annotations.SerializedName; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; import io.reactivex.Observable; import io.reactivex.Single; @@ -134,12 +136,13 @@ import static com.fastaccess.data.dao.model.Gist.OWNER_NAME; return url != null ? url.hashCode() : 0; } - @NonNull public List getFilesAsList() { - List models = new ArrayList<>(); + @NonNull public ArrayList getFilesAsList() { if (files != null) { - models.addAll(files.values()); + return Stream.of(files) + .map(Map.Entry::getValue) + .collect(Collectors.toCollection(ArrayList::new)); } - return models; + return new ArrayList<>(); } @NonNull public SpannableBuilder getDisplayTitle(boolean isFromProfile) { diff --git a/app/src/main/java/com/fastaccess/data/dao/model/AbstractNotification.java b/app/src/main/java/com/fastaccess/data/dao/model/AbstractNotification.java index d7ce2f6a..61657946 100644 --- a/app/src/main/java/com/fastaccess/data/dao/model/AbstractNotification.java +++ b/app/src/main/java/com/fastaccess/data/dao/model/AbstractNotification.java @@ -92,6 +92,26 @@ import lombok.NoArgsConstructor; })).subscribe(o -> {/*do nothing*/}, Throwable::printStackTrace); } + public static Single saveAsSingle(@android.support.annotation.Nullable List models) { + if (models == null || models.isEmpty()) { + return Single.just(true); + } + return RxHelper.getSingle(Single.fromPublisher(s -> { + try { + BlockingEntityStore dataStore = App.getInstance().getDataStore().toBlocking(); + for (Notification entity : models) { + dataStore.delete(Notification.class).where(Notification.ID.eq(entity.getId())).get().value(); + } + dataStore.insert(models); + s.onNext(true); + } catch (Exception e) { + e.printStackTrace(); + s.onError(e); + } + s.onComplete(); + })); + } + public static Single> getUnreadNotifications() { return App.getInstance() .getDataStore() @@ -116,9 +136,9 @@ import lombok.NoArgsConstructor; public static boolean hasUnreadNotifications() { return App.getInstance() .getDataStore() + .toBlocking() .count(Notification.class) .where(Notification.UNREAD.equal(true)) - .limit(1) .get() .value() > 0; } diff --git a/app/src/main/java/com/fastaccess/data/dao/model/AbstractRepo.java b/app/src/main/java/com/fastaccess/data/dao/model/AbstractRepo.java index 33c7833c..4413be49 100644 --- a/app/src/main/java/com/fastaccess/data/dao/model/AbstractRepo.java +++ b/app/src/main/java/com/fastaccess/data/dao/model/AbstractRepo.java @@ -121,13 +121,12 @@ import static com.fastaccess.data.dao.model.Repo.UPDATED_AT; String starredUser; String reposOwner; - public Single save(Repo entity) { - return RxHelper.getSingle(App.getInstance().getDataStore() - .delete(Repo.class) - .where(Repo.ID.eq(entity.getId())) - .get() - .single() - .flatMap(observer -> App.getInstance().getDataStore().insert(entity))); + public Disposable save(Repo entity) { + return Single.create(e -> { + BlockingEntityStore dataSource = App.getInstance().getDataStore().toBlocking(); + dataSource.delete(Repo.class).where(Repo.ID.eq(entity.getId())).get().value(); + dataSource.insert(entity); + }).subscribe(o -> {/**/}, Throwable::printStackTrace); } public static Maybe getRepo(@NonNull String name, @NonNull String login) { diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/AuthorModel.java b/app/src/main/java/com/fastaccess/data/dao/timeline/AuthorModel.java new file mode 100644 index 00000000..fc89b57b --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/AuthorModel.java @@ -0,0 +1,38 @@ +package com.fastaccess.data.dao.timeline; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Date; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter public class AuthorModel implements Parcelable { + private String name; + private String email; + private Date date; + + public AuthorModel() {} + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.name); + dest.writeString(this.email); + dest.writeLong(this.date != null ? this.date.getTime() : -1); + } + + private AuthorModel(Parcel in) { + this.name = in.readString(); + this.email = in.readString(); + long tmpDate = in.readLong(); + this.date = tmpDate == -1 ? null : new Date(tmpDate); + } + + public static final Creator CREATOR = new Creator() { + @Override public AuthorModel createFromParcel(Parcel source) {return new AuthorModel(source);} + + @Override public AuthorModel[] newArray(int size) {return new AuthorModel[size];} + }; +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/CommentEvent.java b/app/src/main/java/com/fastaccess/data/dao/timeline/CommentEvent.java new file mode 100644 index 00000000..4086a577 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/CommentEvent.java @@ -0,0 +1,126 @@ +package com.fastaccess.data.dao.timeline; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.fastaccess.data.dao.ReactionsModel; +import com.fastaccess.data.dao.model.Comment; +import com.fastaccess.data.dao.model.User; + +import java.util.Date; + +import lombok.Getter; +import lombok.Setter; + +/** + * Created by Kosh on 16 Mar 2017, 7:24 PM + */ +@Getter @Setter public class CommentEvent implements Parcelable { + private long id; + private User user; + private String url; + private String body; + private String bodyHtml; + private String htmlUrl; + private Date createdAt; + private Date updatedAt; + private int position; + private int line; + private String path; + private String commitId; + private String repoId; + private String login; + private String gistId; + private String issueId; + private String pullRequestId; + private ReactionsModel reactions; + + @Override public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Comment that = (Comment) o; + return id == that.getId(); + + } + + @Override public int hashCode() { + return (int) (id ^ (id >>> 32)); + } + + public CommentEvent() {} + + @Override public String toString() { + return "CommentEvent{" + + "id=" + id + + ", user=" + user + + ", url='" + url + '\'' + + ", body='" + body + '\'' + + ", bodyHtml='" + bodyHtml + '\'' + + ", htmlUrl='" + htmlUrl + '\'' + + ", createdAt=" + createdAt + + ", updatedAt=" + updatedAt + + ", position=" + position + + ", line=" + line + + ", path='" + path + '\'' + + ", commitId='" + commitId + '\'' + + ", repoId='" + repoId + '\'' + + ", login='" + login + '\'' + + ", gistId='" + gistId + '\'' + + ", issueId='" + issueId + '\'' + + ", pullRequestId='" + pullRequestId + '\'' + + ", reactions=" + reactions + + '}'; + } + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(this.id); + dest.writeParcelable(this.user, flags); + dest.writeString(this.url); + dest.writeString(this.body); + dest.writeString(this.bodyHtml); + dest.writeString(this.htmlUrl); + dest.writeLong(this.createdAt != null ? this.createdAt.getTime() : -1); + dest.writeLong(this.updatedAt != null ? this.updatedAt.getTime() : -1); + dest.writeInt(this.position); + dest.writeInt(this.line); + dest.writeString(this.path); + dest.writeString(this.commitId); + dest.writeString(this.repoId); + dest.writeString(this.login); + dest.writeString(this.gistId); + dest.writeString(this.issueId); + dest.writeString(this.pullRequestId); + dest.writeParcelable(this.reactions, flags); + } + + private CommentEvent(Parcel in) { + this.id = in.readLong(); + this.user = in.readParcelable(User.class.getClassLoader()); + this.url = in.readString(); + this.body = in.readString(); + this.bodyHtml = in.readString(); + this.htmlUrl = in.readString(); + long tmpCreatedAt = in.readLong(); + this.createdAt = tmpCreatedAt == -1 ? null : new Date(tmpCreatedAt); + long tmpUpdatedAt = in.readLong(); + this.updatedAt = tmpUpdatedAt == -1 ? null : new Date(tmpUpdatedAt); + this.position = in.readInt(); + this.line = in.readInt(); + this.path = in.readString(); + this.commitId = in.readString(); + this.repoId = in.readString(); + this.login = in.readString(); + this.gistId = in.readString(); + this.issueId = in.readString(); + this.pullRequestId = in.readString(); + this.reactions = in.readParcelable(ReactionsModel.class.getClassLoader()); + } + + public static final Creator CREATOR = new Creator() { + @Override public CommentEvent createFromParcel(Parcel source) {return new CommentEvent(source);} + + @Override public CommentEvent[] newArray(int size) {return new CommentEvent[size];} + }; +} diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/GenericEvent.java b/app/src/main/java/com/fastaccess/data/dao/timeline/GenericEvent.java new file mode 100644 index 00000000..a5d4c86b --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/GenericEvent.java @@ -0,0 +1,119 @@ +package com.fastaccess.data.dao.timeline; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.fastaccess.data.dao.LabelModel; +import com.fastaccess.data.dao.MilestoneModel; +import com.fastaccess.data.dao.RenameModel; +import com.fastaccess.data.dao.TeamsModel; +import com.fastaccess.data.dao.model.Issue; +import com.fastaccess.data.dao.model.PullRequest; +import com.fastaccess.data.dao.model.User; +import com.fastaccess.data.dao.types.IssueEventType; + +import java.util.Date; +import java.util.List; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * Created by kosh on 25/07/2017. + */ + +@NoArgsConstructor @Getter @Setter public class GenericEvent implements Parcelable { + + private long id; + private String url; + private String commitId; + private String commitUrl; + private String message; + private String sha; + private String htmlUrl; + private Date createdAt; + private User actor; + private User requestedReviewer; + private User reviewRequester; + private User assigner; + private User assignee; + private User author; + private User committer; + private LabelModel label; + private TeamsModel requestedTeam; + private MilestoneModel milestone; + private RenameModel rename; + private SourceModel source; + private Issue issue; + private PullRequest pullRequest; + private ParentsModel tree; + private List parents; + private IssueEventType event; + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(this.id); + dest.writeString(this.url); + dest.writeString(this.commitId); + dest.writeString(this.commitUrl); + dest.writeString(this.message); + dest.writeString(this.sha); + dest.writeString(this.htmlUrl); + dest.writeLong(this.createdAt != null ? this.createdAt.getTime() : -1); + dest.writeParcelable(this.actor, flags); + dest.writeParcelable(this.requestedReviewer, flags); + dest.writeParcelable(this.reviewRequester, flags); + dest.writeParcelable(this.assigner, flags); + dest.writeParcelable(this.assignee, flags); + dest.writeParcelable(this.author, flags); + dest.writeParcelable(this.committer, flags); + dest.writeParcelable(this.label, flags); + dest.writeParcelable(this.requestedTeam, flags); + dest.writeParcelable(this.milestone, flags); + dest.writeParcelable(this.rename, flags); + dest.writeParcelable(this.source, flags); + dest.writeParcelable(this.issue, flags); + dest.writeParcelable(this.pullRequest, flags); + dest.writeParcelable(this.tree, flags); + dest.writeTypedList(this.parents); + dest.writeInt(this.event == null ? -1 : this.event.ordinal()); + } + + private GenericEvent(Parcel in) { + this.id = in.readLong(); + this.url = in.readString(); + this.commitId = in.readString(); + this.commitUrl = in.readString(); + this.message = in.readString(); + this.sha = in.readString(); + this.htmlUrl = in.readString(); + long tmpCreatedAt = in.readLong(); + this.createdAt = tmpCreatedAt == -1 ? null : new Date(tmpCreatedAt); + this.actor = in.readParcelable(User.class.getClassLoader()); + this.requestedReviewer = in.readParcelable(User.class.getClassLoader()); + this.reviewRequester = in.readParcelable(User.class.getClassLoader()); + this.assigner = in.readParcelable(User.class.getClassLoader()); + this.assignee = in.readParcelable(User.class.getClassLoader()); + this.author = in.readParcelable(User.class.getClassLoader()); + this.committer = in.readParcelable(User.class.getClassLoader()); + this.label = in.readParcelable(LabelModel.class.getClassLoader()); + this.requestedTeam = in.readParcelable(TeamsModel.class.getClassLoader()); + this.milestone = in.readParcelable(MilestoneModel.class.getClassLoader()); + this.rename = in.readParcelable(RenameModel.class.getClassLoader()); + this.source = in.readParcelable(SourceModel.class.getClassLoader()); + this.issue = in.readParcelable(Issue.class.getClassLoader()); + this.pullRequest = in.readParcelable(PullRequest.class.getClassLoader()); + this.tree = in.readParcelable(ParentsModel.class.getClassLoader()); + this.parents = in.createTypedArrayList(ParentsModel.CREATOR); + int tmpEvent = in.readInt(); + this.event = tmpEvent == -1 ? null : IssueEventType.values()[tmpEvent]; + } + + public static final Creator CREATOR = new Creator() { + @Override public GenericEvent createFromParcel(Parcel source) {return new GenericEvent(source);} + + @Override public GenericEvent[] newArray(int size) {return new GenericEvent[size];} + }; +} diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/ParentsModel.java b/app/src/main/java/com/fastaccess/data/dao/timeline/ParentsModel.java new file mode 100644 index 00000000..9c091d98 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/ParentsModel.java @@ -0,0 +1,35 @@ +package com.fastaccess.data.dao.timeline; + +import android.os.Parcel; +import android.os.Parcelable; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter public class ParentsModel implements Parcelable { + private String sha; + private String url; + private String htmlUrl; + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.sha); + dest.writeString(this.url); + dest.writeString(this.htmlUrl); + } + + public ParentsModel() {} + + private ParentsModel(Parcel in) { + this.sha = in.readString(); + this.url = in.readString(); + this.htmlUrl = in.readString(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override public ParentsModel createFromParcel(Parcel source) {return new ParentsModel(source);} + + @Override public ParentsModel[] newArray(int size) {return new ParentsModel[size];} + }; +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestCommitModel.java b/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestCommitModel.java new file mode 100644 index 00000000..d17c6bb2 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestCommitModel.java @@ -0,0 +1,98 @@ +package com.fastaccess.data.dao.timeline; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.fastaccess.data.dao.model.Comment; + +import java.util.List; + +/** + * Created by kosh on 15/08/2017. + */ + +public class PullRequestCommitModel implements Parcelable { + private String login; + private String path; + private int position; + private String commitId; + private List comments; + private int line; + + + public int getLine() { + return line; + } + + public void setLine(int line) { + this.line = line; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public String getCommitId() { + return commitId; + } + + public void setCommitId(String commitId) { + this.commitId = commitId; + } + + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + + public PullRequestCommitModel() {} + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.login); + dest.writeString(this.path); + dest.writeInt(this.position); + dest.writeString(this.commitId); + dest.writeTypedList(this.comments); + dest.writeInt(this.line); + } + + protected PullRequestCommitModel(Parcel in) { + this.login = in.readString(); + this.path = in.readString(); + this.position = in.readInt(); + this.commitId = in.readString(); + this.comments = in.createTypedArrayList(Comment.CREATOR); + this.line = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override public PullRequestCommitModel createFromParcel(Parcel source) {return new PullRequestCommitModel(source);} + + @Override public PullRequestCommitModel[] newArray(int size) {return new PullRequestCommitModel[size];} + }; +} diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestReviewModel.java b/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestReviewModel.java new file mode 100644 index 00000000..63889376 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestReviewModel.java @@ -0,0 +1,169 @@ +package com.fastaccess.data.dao.timeline; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.fastaccess.data.dao.ReactionsModel; +import com.fastaccess.helper.Logger; +import com.fastaccess.helper.ParseDateFormat; + +import java.util.ArrayList; +import java.util.List; + +import pr.PullRequestTimelineQuery; +import pr.type.PullRequestReviewState; + +/** + * Created by kosh on 20/08/2017. + */ + +public class PullRequestReviewModel { + private PullRequestTimelineQuery.AsReviewDismissedEvent reviewDismissedEvent; + private PullRequestTimelineQuery.AsReviewRequestedEvent reviewRequestedEvent; + private PullRequestTimelineQuery.AsReviewRequestRemovedEvent reviewRequestRemovedEvent; + private PullRequestTimelineQuery.Node2 node; + private List reaction; + private List comments; + private String id; + private String url; + private PullRequestTimelineQuery.Author2 author; + private String bodyHTML; + private String createdAt; + private PullRequestReviewState state; + + @Nullable public static PullRequestReviewModel build(@NonNull PullRequestTimelineQuery.Node node) { + PullRequestReviewModel model = new PullRequestReviewModel(); + if (node.asReviewRequestRemovedEvent() != null) { + model.reviewRequestRemovedEvent = node.asReviewRequestRemovedEvent(); + } else if (node.asReviewDismissedEvent() != null) { + model.reviewDismissedEvent = node.asReviewDismissedEvent(); + } else if (node.asReviewRequestedEvent() != null) { + model.reviewRequestedEvent = node.asReviewRequestedEvent(); + } else { + PullRequestTimelineQuery.AsPullRequestReview pullRequestReview = node.asPullRequestReview(); + if (pullRequestReview != null) { + model.state = pullRequestReview.state(); + model.url = pullRequestReview.url().toString(); + model.author = pullRequestReview.author(); + model.bodyHTML = pullRequestReview.bodyHTML().toString(); + model.createdAt = ParseDateFormat.getTimeAgo(pullRequestReview.createdAt().toString()).toString(); + model.id = pullRequestReview.id(); + model.url = pullRequestReview.url().toString(); + List edges = pullRequestReview.comments().edges(); + if (edges != null && !edges.isEmpty()) { + List comments = new ArrayList<>(); + for (PullRequestTimelineQuery.Edge2 edge : edges) { + PullRequestTimelineQuery.Node2 node2 = edge.node(); + if (node2 != null) { + PullRequestReviewModel comment = new PullRequestReviewModel(); + comment.node = node2; + comment.reaction = ReactionsModel.getReaction(node2.reactionGroups()); + comments.add(comment); + } + } + Logger.e(comments.size()); + model.comments = comments; + } + } else { + return null; + } + } + return model; + } + + public PullRequestTimelineQuery.AsReviewDismissedEvent getReviewDismissedEvent() { + return reviewDismissedEvent; + } + + public void setReviewDismissedEvent(PullRequestTimelineQuery.AsReviewDismissedEvent reviewDismissedEvent) { + this.reviewDismissedEvent = reviewDismissedEvent; + } + + public PullRequestTimelineQuery.AsReviewRequestedEvent getReviewRequestedEvent() { + return reviewRequestedEvent; + } + + public void setReviewRequestedEvent(PullRequestTimelineQuery.AsReviewRequestedEvent reviewRequestedEvent) { + this.reviewRequestedEvent = reviewRequestedEvent; + } + + public PullRequestTimelineQuery.AsReviewRequestRemovedEvent getReviewRequestRemovedEvent() { + return reviewRequestRemovedEvent; + } + + public void setReviewRequestRemovedEvent(PullRequestTimelineQuery.AsReviewRequestRemovedEvent reviewRequestRemovedEvent) { + this.reviewRequestRemovedEvent = reviewRequestRemovedEvent; + } + + public PullRequestTimelineQuery.Node2 getNode() { + return node; + } + + public void setNode(PullRequestTimelineQuery.Node2 node) { + this.node = node; + } + + public List getReaction() { + return reaction; + } + + public void setReaction(List reaction) { + this.reaction = reaction; + } + + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public PullRequestTimelineQuery.Author2 getAuthor() { + return author; + } + + public void setAuthor(PullRequestTimelineQuery.Author2 author) { + this.author = author; + } + + public String getBodyHTML() { + return bodyHTML; + } + + public void setBodyHTML(String bodyHTML) { + this.bodyHTML = bodyHTML; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public PullRequestReviewState getState() { + return state; + } + + public void setState(PullRequestReviewState state) { + this.state = state; + } +} diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestTimelineModel.java b/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestTimelineModel.java new file mode 100644 index 00000000..fcddb8f9 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/PullRequestTimelineModel.java @@ -0,0 +1,85 @@ +package com.fastaccess.data.dao.timeline; + +import com.fastaccess.data.dao.ReactionsModel; +import com.fastaccess.data.dao.model.PullRequest; + +import java.util.List; + +import lombok.Getter; +import lombok.Setter; +import pr.PullRequestTimelineQuery; + +/** + * Created by kosh on 02/08/2017. + */ + +@Getter @Setter public class PullRequestTimelineModel { + + public static final int HEADER = 1; + public static final int EVENT = 2; + public static final int COMMENT = 3; + public static final int STATUS = 4; + public static final int REVIEW = 5; + public static final int COMMIT_COMMENTS = 6; + public PullRequestTimelineQuery.Node node; + public PullRequest pullRequest; + public PullRequestTimelineQuery.Status status; + public List reactions; + public boolean isMergeable; + public PullRequestCommitModel commitThread; + public PullRequestReviewModel reviewModel; + + public PullRequestTimelineModel(PullRequest pullRequest) { + this.pullRequest = pullRequest; + } + + public PullRequestTimelineModel(PullRequestTimelineQuery.Node node) { + this.node = node; + if (this.node.asCommitCommentThread() != null) { + + } else { + if (node.asPullRequestReview() != null || node.asReviewDismissedEvent() != null + || node.asReviewRequestedEvent() != null || node.asReviewRequestRemovedEvent() != null) { + reviewModel = PullRequestReviewModel.build(node); + } + } + } + + public PullRequestTimelineModel(PullRequestTimelineQuery.Status status, boolean isMergeable) { + this.status = status; + this.isMergeable = isMergeable; + } + + public int getType() { + if (pullRequest != null) return HEADER; + if (node != null) { + if (node.asAssignedEvent() != null || node.asClosedEvent() != null + || node.asDemilestonedEvent() != null || node.asHeadRefDeletedEvent() != null + || node.asLabeledEvent() != null || node.asLockedEvent() != null + || node.asMergedEvent() != null || node.asMilestonedEvent() != null + || node.asReferencedEvent() != null || node.asRenamedTitleEvent() != null + || node.asReopenedEvent() != null || node.asUnassignedEvent() != null + || node.asUnlabeledEvent() != null || node.asUnlockedEvent() != null + || node.asCommit() != null || node.asHeadRefRestoredEvent() != null) { + return EVENT; + } else if (node.asIssueComment() != null) { + if (reactions == null) { + //noinspection ConstantConditions + setReactions(ReactionsModel.getReaction2(node.asIssueComment().reactionGroups())); + } + return COMMENT; + } else if (reviewModel != null) { + return REVIEW; + } else if (commitThread != null) { + return COMMIT_COMMENTS; + } + } else if (status != null) { + return STATUS; + } + return 0; + } + + @Override public String toString() { + return String.valueOf(getType()); + } +} diff --git a/app/src/main/java/com/fastaccess/data/dao/timeline/SourceModel.java b/app/src/main/java/com/fastaccess/data/dao/timeline/SourceModel.java new file mode 100644 index 00000000..3efcfe06 --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/timeline/SourceModel.java @@ -0,0 +1,51 @@ +package com.fastaccess.data.dao.timeline; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.fastaccess.data.dao.model.Commit; +import com.fastaccess.data.dao.model.Issue; +import com.fastaccess.data.dao.model.PullRequest; +import com.fastaccess.data.dao.model.Repo; + +import lombok.Getter; +import lombok.Setter; + +/** + * Created by kosh on 26/07/2017. + */ + +@Getter @Setter public class SourceModel implements Parcelable { + + private String type; + private Issue issue; + private PullRequest pullRequest; + private Commit commit; + private Repo repository; + + public SourceModel() {} + + @Override public int describeContents() { return 0; } + + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.type); + dest.writeParcelable(this.issue, flags); + dest.writeParcelable(this.pullRequest, flags); + dest.writeParcelable(this.commit, flags); + dest.writeParcelable(this.repository, flags); + } + + private SourceModel(Parcel in) { + this.type = in.readString(); + this.issue = in.readParcelable(Issue.class.getClassLoader()); + this.pullRequest = in.readParcelable(PullRequest.class.getClassLoader()); + this.commit = in.readParcelable(Commit.class.getClassLoader()); + this.repository = in.readParcelable(Repo.class.getClassLoader()); + } + + public static final Creator CREATOR = new Creator() { + @Override public SourceModel createFromParcel(Parcel source) {return new SourceModel(source);} + + @Override public SourceModel[] newArray(int size) {return new SourceModel[size];} + }; +} diff --git a/app/src/main/java/com/fastaccess/data/dao/types/IssueEventType.java b/app/src/main/java/com/fastaccess/data/dao/types/IssueEventType.java index b841e2c2..525029e0 100644 --- a/app/src/main/java/com/fastaccess/data/dao/types/IssueEventType.java +++ b/app/src/main/java/com/fastaccess/data/dao/types/IssueEventType.java @@ -1,5 +1,9 @@ package com.fastaccess.data.dao.types; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.annimon.stream.Stream; import com.fastaccess.R; import com.google.gson.annotations.SerializedName; @@ -7,7 +11,7 @@ public enum IssueEventType { assigned(R.drawable.ic_profile), closed(R.drawable.ic_issue_closed), commented(R.drawable.ic_comment), - committed(R.drawable.ic_announcement), + committed(R.drawable.ic_push), demilestoned(R.drawable.ic_milestone), head_ref_deleted(R.drawable.ic_trash), head_ref_restored(R.drawable.ic_redo), @@ -27,7 +31,13 @@ public enum IssueEventType { review_requested(R.drawable.ic_eye), review_dismissed(R.drawable.ic_eye_off), review_request_removed(R.drawable.ic_eye_off), - @SerializedName("cross-referenced")crossReferenced(R.drawable.ic_format_quote); + @SerializedName("cross-referenced")cross_referenced(R.drawable.ic_format_quote), + @SerializedName("line-commented")line_commented(R.drawable.ic_comment), + @SerializedName("commit-commented")commit_commented(R.drawable.ic_comment), + reviewed(R.drawable.ic_eye), + changes_requested(R.drawable.ic_eye), + added_to_project(R.drawable.ic_add), + GROUPED(R.drawable.ic_eye); int iconResId; @@ -36,4 +46,12 @@ public enum IssueEventType { public int getIconResId() { return iconResId == 0 ? R.drawable.ic_label : iconResId; } + + @Nullable public static IssueEventType getType(@NonNull String type) { + return Stream.of(values()) + .filter(value -> value.name().toLowerCase().equalsIgnoreCase(type.toLowerCase() + .replaceAll("-", "_"))) + .findFirst() + .orElse(null); + } } \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/data/dao/types/ReactionTypes.java b/app/src/main/java/com/fastaccess/data/dao/types/ReactionTypes.java index bc2c0c09..306bbf3a 100644 --- a/app/src/main/java/com/fastaccess/data/dao/types/ReactionTypes.java +++ b/app/src/main/java/com/fastaccess/data/dao/types/ReactionTypes.java @@ -3,6 +3,7 @@ package com.fastaccess.data.dao.types; import android.support.annotation.IdRes; import android.support.annotation.Nullable; +import com.annimon.stream.Stream; import com.fastaccess.R; /** @@ -35,10 +36,9 @@ public enum ReactionTypes { } @Nullable public static ReactionTypes get(@IdRes int vId) { - for (ReactionTypes type : ReactionTypes.values()) { - if (type.vId == vId) return type; - } - - return null; + return Stream.of(values()) + .filter(value -> value.getvId() == vId) + .findFirst() + .orElse(null); } } diff --git a/app/src/main/java/com/fastaccess/data/dao/types/ReviewStateType.java b/app/src/main/java/com/fastaccess/data/dao/types/ReviewStateType.java index 76f83ca9..da91a590 100644 --- a/app/src/main/java/com/fastaccess/data/dao/types/ReviewStateType.java +++ b/app/src/main/java/com/fastaccess/data/dao/types/ReviewStateType.java @@ -1,8 +1,11 @@ package com.fastaccess.data.dao.types; import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.StringRes; +import com.annimon.stream.Stream; import com.fastaccess.R; /** @@ -11,7 +14,7 @@ import com.fastaccess.R; public enum ReviewStateType { COMMENTED(R.string.reviewed, R.drawable.ic_eye), - CHANGES_REQUESTED(R.string.reviewed, R.drawable.ic_eye), + CHANGES_REQUESTED(R.string.request_changes, R.drawable.ic_clear), REQUEST_CHANGES(R.string.reviewed, R.drawable.ic_eye), DISMISSED(R.string.dismissed_review, R.drawable.ic_clear), APPROVED(R.string.approved_these_changes, R.drawable.ic_done), @@ -32,4 +35,11 @@ public enum ReviewStateType { @DrawableRes public int getDrawableRes() { return drawableRes > 0 ? drawableRes : R.drawable.ic_eye; } + + @Nullable public static ReviewStateType getType(@NonNull String state) { + return Stream.of(values()) + .filter(value -> value.name().toLowerCase().equalsIgnoreCase(state.toLowerCase())) + .findFirst() + .orElse(null); + } } diff --git a/app/src/main/java/com/fastaccess/data/dao/types/StatusStateType.java b/app/src/main/java/com/fastaccess/data/dao/types/StatusStateType.java index c7ec2beb..ae02006b 100644 --- a/app/src/main/java/com/fastaccess/data/dao/types/StatusStateType.java +++ b/app/src/main/java/com/fastaccess/data/dao/types/StatusStateType.java @@ -1,7 +1,10 @@ package com.fastaccess.data.dao.types; import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.annimon.stream.Stream; import com.fastaccess.R; /** @@ -23,4 +26,11 @@ public enum StatusStateType { @DrawableRes public int getDrawableRes() { return drawableRes; } + + @NonNull public static StatusStateType getState(@Nullable String status) { + return Stream.of(values()) + .filter(value -> value.name().toLowerCase().equalsIgnoreCase(status)) + .findFirst() + .orElse(pending); + } } diff --git a/app/src/main/java/com/fastaccess/data/dao/wiki/WikiContentModel.kt b/app/src/main/java/com/fastaccess/data/dao/wiki/WikiContentModel.kt index 4428ea5c..a8cc9162 100644 --- a/app/src/main/java/com/fastaccess/data/dao/wiki/WikiContentModel.kt +++ b/app/src/main/java/com/fastaccess/data/dao/wiki/WikiContentModel.kt @@ -6,7 +6,7 @@ import android.os.Parcelable /** * Created by Kosh on 13 Jun 2017, 8:06 PM */ -data class WikiContentModel(val content: String? = null, val footer: String? = null, +data class WikiContentModel(val content: String? = null, private val footer: String? = null, val sidebar: ArrayList) : Parcelable { companion object { @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { diff --git a/app/src/main/java/com/fastaccess/data/service/GistService.java b/app/src/main/java/com/fastaccess/data/service/GistService.java index bc088be4..77745d6b 100644 --- a/app/src/main/java/com/fastaccess/data/service/GistService.java +++ b/app/src/main/java/com/fastaccess/data/service/GistService.java @@ -32,7 +32,7 @@ public interface GistService { @POST("gists") Observable createGist(@Body CreateGistModel gistBody); - @POST("gists/{id}") Observable editGist(@Body CreateGistModel gistBody, @NonNull @Path("id") String id); + @PATCH("gists/{id}") Observable editGist(@Body CreateGistModel gistBody, @Path("id") String id); @DELETE("gists/{id}") Observable> deleteGist(@Path("id") String id); diff --git a/app/src/main/java/com/fastaccess/data/service/IssueService.java b/app/src/main/java/com/fastaccess/data/service/IssueService.java index 82767c18..6a8835db 100644 --- a/app/src/main/java/com/fastaccess/data/service/IssueService.java +++ b/app/src/main/java/com/fastaccess/data/service/IssueService.java @@ -7,14 +7,17 @@ import com.fastaccess.data.dao.AssigneesRequestModel; import com.fastaccess.data.dao.CommentRequestModel; import com.fastaccess.data.dao.CreateIssueModel; import com.fastaccess.data.dao.IssueRequestModel; +import com.fastaccess.data.dao.IssuesPageable; import com.fastaccess.data.dao.LabelModel; import com.fastaccess.data.dao.Pageable; import com.fastaccess.data.dao.model.Comment; import com.fastaccess.data.dao.model.Issue; import com.fastaccess.data.dao.model.IssueEvent; +import com.google.gson.JsonObject; import java.util.List; +import io.reactivex.Observable; import retrofit2.Response; import retrofit2.http.Body; import retrofit2.http.DELETE; @@ -25,7 +28,6 @@ import retrofit2.http.POST; import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; -import io.reactivex.Observable; public interface IssueService { @@ -49,6 +51,12 @@ public interface IssueService { Observable> getTimeline(@Path("owner") String owner, @Path("repo") String repo, @Path("issue_number") int issue_number); + @GET("repos/{owner}/{repo}/issues/{issue_number}/timeline") + @Headers("Accept: application/vnd.github.mockingbird-preview,application/vnd.github.VERSION.full+json," + + " application/vnd.github.squirrel-girl-preview") + Observable> getTimeline(@Path("owner") String owner, @Path("repo") String repo, + @Path("issue_number") int issue_number, @Query("page") int page); + @POST("repos/{owner}/{repo}/issues") Observable createIssue(@Path("owner") String owner, @Path("repo") String repo, @Body IssueRequestModel issue); diff --git a/app/src/main/java/com/fastaccess/data/service/OrganizationService.java b/app/src/main/java/com/fastaccess/data/service/OrganizationService.java index 07d6b29b..f4b64f10 100644 --- a/app/src/main/java/com/fastaccess/data/service/OrganizationService.java +++ b/app/src/main/java/com/fastaccess/data/service/OrganizationService.java @@ -39,10 +39,13 @@ public interface OrganizationService { @GET("teams/{id}/repos") Observable> getTeamRepos(@Path("id") long id, @Query("page") int page); - @GET("orgs/{username}/events") - Observable> getReceivedEvents(@NonNull @Path("username") String userName, @Query("page") int page); + @GET("users/{username}/events/orgs/{org}") + Observable> getReceivedEvents(@NonNull @Path("username") String userName, + @NonNull @Path("org") String org, @Query("page") int page); @GET("orgs/{org}/repos") - Observable> getOrgRepos(@NonNull @Path("org") String org, @QueryMap(encoded = true) Map filterParams, @Query("page") int page); + Observable> getOrgRepos(@NonNull @Path("org") String org, + @QueryMap(encoded = true) Map filterParams, + @Query("page") int page); } diff --git a/app/src/main/java/com/fastaccess/data/service/RepoService.java b/app/src/main/java/com/fastaccess/data/service/RepoService.java index ef48da02..e1d64e80 100644 --- a/app/src/main/java/com/fastaccess/data/service/RepoService.java +++ b/app/src/main/java/com/fastaccess/data/service/RepoService.java @@ -138,6 +138,9 @@ public interface RepoService { @NonNull @GET("repos/{owner}/{repo}/labels?per_page=100") Observable> getLabels(@NonNull @Path("owner") String owner, @NonNull @Path("repo") String repo); + @NonNull @GET("repos/{owner}/{repo}/labels?per_page=100") + Observable> getLabels(@NonNull @Path("owner") String owner, @NonNull @Path("repo") String repo, @Query("page") int page); + @NonNull @POST("repos/{owner}/{repo}/labels") Observable addLabel(@NonNull @Path("owner") String owner, @NonNull @Path("repo") String repo, @Body LabelModel body); diff --git a/app/src/main/java/com/fastaccess/data/service/ReviewService.java b/app/src/main/java/com/fastaccess/data/service/ReviewService.java index 3d495bae..8d947c36 100644 --- a/app/src/main/java/com/fastaccess/data/service/ReviewService.java +++ b/app/src/main/java/com/fastaccess/data/service/ReviewService.java @@ -42,7 +42,7 @@ public interface ReviewService { Observable> getReviewComments(@Path("owner") String owner, @Path("repo") String repo, @Path("number") long number, @Path("id") long reviewId); - @GET("repos/{owner}/{repo}/pulls/{number}/comments") + @GET("repos/{owner}/{repo}/pulls/{number}/comments?per_page=100") @Headers("Accept: application/vnd.github.black-cat-preview+json, application/vnd.github.VERSION.html, " + "application/vnd.github.squirrel-girl-preview") @NonNull @@ -68,5 +68,5 @@ public interface ReviewService { @POST("repos/{owner}/{repo}/pulls/{number}/reviews") @Headers("Accept: application/vnd.github.black-cat-preview") Observable> submitPrReview(@Path("owner") String owner, @Path("repo") String repo, - @Path("number") long number, @NonNull @Body ReviewRequestModel body); + @Path("number") long number, @NonNull @Body ReviewRequestModel body); } diff --git a/app/src/main/java/com/fastaccess/helper/AppHelper.java b/app/src/main/java/com/fastaccess/helper/AppHelper.java index ee48697c..9768accd 100644 --- a/app/src/main/java/com/fastaccess/helper/AppHelper.java +++ b/app/src/main/java/com/fastaccess/helper/AppHelper.java @@ -4,6 +4,8 @@ import android.app.NotificationManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; @@ -73,14 +75,16 @@ public class AppHelper { .append("**Android Version: ").append(String.valueOf(Build.VERSION.RELEASE)).append(" (SDK: ") .append(String.valueOf(Build.VERSION.SDK_INT)).append(")**").append(" \n") .append("**Device Information:**").append(" \n") - .append("- **" + (!model.equalsIgnoreCase(brand) ? "Manufacturer" : "Manufacturer&Brand") + ":** ").append(Build.MANUFACTURER) + .append("- **") + .append(!model.equalsIgnoreCase(brand) ? "Manufacturer" : "Manufacturer&Brand") + .append(":** ") + .append(Build.MANUFACTURER) .append(" \n"); if (!(model.equalsIgnoreCase(brand) || "google".equals(Build.BRAND))) { builder.append("- **Brand:** ").append(brand).append(" \n"); } - builder.append("- **Model:** ") - .append(model) - .append(" \n").append("---").append("\n"); + builder.append("- **Model:** ").append(model).append(" \n") + .append("---").append("\n\n"); if (!Locale.getDefault().getLanguage().equals(new Locale("en").getLanguage())) { builder.append("<--") .append(App.getInstance().getString(R.string.english_please)) @@ -157,7 +161,13 @@ public class AppHelper { } public static boolean isGoogleAvailable(@NonNull Context context) { - int status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); - return status != ConnectionResult.SERVICE_DISABLED && status == ConnectionResult.SUCCESS; + ApplicationInfo applicationInfo = null; + try { + applicationInfo = context.getPackageManager().getApplicationInfo("com.google.android.gms", 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return applicationInfo != null && applicationInfo.enabled && + GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS; } } \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/helper/BundleConstant.java b/app/src/main/java/com/fastaccess/helper/BundleConstant.java index 5141828d..14281c7d 100644 --- a/app/src/main/java/com/fastaccess/helper/BundleConstant.java +++ b/app/src/main/java/com/fastaccess/helper/BundleConstant.java @@ -5,9 +5,15 @@ import android.support.annotation.StringDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.EDIT_GIST_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.FOR_RESULT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.NEW_GIST_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.EDIT_COMMIT_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.EDIT_GIST_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.EDIT_ISSUE_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.EDIT_REVIEW_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.FOR_RESULT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.NEW_COMMIT_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.NEW_GIST_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.NEW_ISSUE_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.NEW_REVIEW_COMMENT_EXTRA; /** * Created by Kosh on 12 Nov 2016, 3:55 PM @@ -35,12 +41,18 @@ public class BundleConstant { @StringDef({ - NEW_GIST_COMMENT_EXTRA, + FOR_RESULT_EXTRA, EDIT_GIST_COMMENT_EXTRA, - FOR_RESULT_EXTRA + NEW_GIST_COMMENT_EXTRA, + EDIT_ISSUE_COMMENT_EXTRA, + NEW_ISSUE_COMMENT_EXTRA, + EDIT_COMMIT_COMMENT_EXTRA, + NEW_COMMIT_COMMENT_EXTRA, + NEW_REVIEW_COMMENT_EXTRA, + EDIT_REVIEW_COMMENT_EXTRA }) - @Retention(RetentionPolicy.SOURCE) public @interface ExtraTYpe { + @Retention(RetentionPolicy.SOURCE) public @interface ExtraType { String FOR_RESULT_EXTRA = "for_result_extra"; String EDIT_GIST_COMMENT_EXTRA = "edit_comment_extra"; String NEW_GIST_COMMENT_EXTRA = "new_gist_comment_extra"; diff --git a/app/src/main/java/com/fastaccess/helper/Bundler.java b/app/src/main/java/com/fastaccess/helper/Bundler.java index 8f682783..409819f0 100644 --- a/app/src/main/java/com/fastaccess/helper/Bundler.java +++ b/app/src/main/java/com/fastaccess/helper/Bundler.java @@ -185,7 +185,7 @@ public class Bundler { /** * Get the underlying start. */ - public Bundle get() { + private Bundle get() { return bundle; } diff --git a/app/src/main/java/com/fastaccess/helper/CustomTabsHelper.java b/app/src/main/java/com/fastaccess/helper/CustomTabsHelper.java index e90232b5..722820ed 100644 --- a/app/src/main/java/com/fastaccess/helper/CustomTabsHelper.java +++ b/app/src/main/java/com/fastaccess/helper/CustomTabsHelper.java @@ -12,7 +12,7 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; -public class CustomTabsHelper { +class CustomTabsHelper { private static final String TAG = "CustomTabsHelper"; private static final String STABLE_PACKAGE = "com.android.chrome"; private static final String BETA_PACKAGE = "com.chrome.beta"; diff --git a/app/src/main/java/com/fastaccess/helper/ParseDateFormat.java b/app/src/main/java/com/fastaccess/helper/ParseDateFormat.java index d828b4ba..eba702cc 100644 --- a/app/src/main/java/com/fastaccess/helper/ParseDateFormat.java +++ b/app/src/main/java/com/fastaccess/helper/ParseDateFormat.java @@ -31,6 +31,18 @@ public class ParseDateFormat { } } + + @NonNull public static CharSequence getTimeAgo(@Nullable String toParse) { + try { + Date parsedDate = getInstance().dateFormat.parse(toParse); + long now = System.currentTimeMillis(); + return DateUtils.getRelativeTimeSpanString(parsedDate.getTime(), now, DateUtils.SECOND_IN_MILLIS); + } catch (Exception e) { + e.printStackTrace(); + } + return "N/A"; + } + @NonNull public static CharSequence getTimeAgo(@Nullable Date parsedDate) { if (parsedDate != null) { long now = System.currentTimeMillis(); diff --git a/app/src/main/java/com/fastaccess/provider/emoji/Emoji.java b/app/src/main/java/com/fastaccess/provider/emoji/Emoji.java index f89944b5..8f46fdb8 100644 --- a/app/src/main/java/com/fastaccess/provider/emoji/Emoji.java +++ b/app/src/main/java/com/fastaccess/provider/emoji/Emoji.java @@ -3,6 +3,7 @@ package com.fastaccess.provider.emoji; import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * This class represents an emoji.
@@ -12,203 +13,205 @@ import java.util.List; * @author Vincent DURMONT [vdurmont@gmail.com] */ public class Emoji { - private final String description; - private final boolean supportsFitzpatrick; - private final List aliases; - private final List tags; - private final String unicode; - private final String htmlDec; - private final String htmlHex; + private final String description; + private final boolean supportsFitzpatrick; + private final List aliases; + private final List tags; + private String unicode; + private String htmlDec; + private String htmlHex; - /** - * Constructor for the Emoji. - * - * @param description The description of the emoji - * @param supportsFitzpatrick Whether the emoji supports Fitzpatrick modifiers - * @param aliases the aliases for this emoji - * @param tags the tags associated with this emoji - * @param bytes the bytes that represent the emoji - */ - protected Emoji( - String description, - boolean supportsFitzpatrick, - List aliases, - List tags, - byte... bytes - ) { - this.description = description; - this.supportsFitzpatrick = supportsFitzpatrick; - this.aliases = Collections.unmodifiableList(aliases); - this.tags = Collections.unmodifiableList(tags); + /** + * Constructor for the Emoji. + * + * @param description + * The description of the emoji + * @param supportsFitzpatrick + * Whether the emoji supports Fitzpatrick modifiers + * @param aliases + * the aliases for this emoji + * @param tags + * the tags associated with this emoji + * @param bytes + * the bytes that represent the emoji + */ + protected Emoji( + String description, + boolean supportsFitzpatrick, + List aliases, + List tags, + byte... bytes + ) { + this.description = description; + this.supportsFitzpatrick = supportsFitzpatrick; + this.aliases = Collections.unmodifiableList(aliases); + this.tags = Collections.unmodifiableList(tags); - int count = 0; - try { - this.unicode = new String(bytes, "UTF-8"); - int stringLength = getUnicode().length(); - String[] pointCodes = new String[stringLength]; - String[] pointCodesHex = new String[stringLength]; - - for (int offset = 0; offset < stringLength; ) { - final int codePoint = getUnicode().codePointAt(offset); - - pointCodes[count] = String.format("&#%d;", codePoint); - pointCodesHex[count++] = String.format("&#x%x;", codePoint); - - offset += Character.charCount(codePoint); - } - this.htmlDec = stringJoin(pointCodes, count); - this.htmlHex = stringJoin(pointCodesHex, count); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + int count = 0; + try { + this.unicode = new String(bytes, "UTF-8"); + int stringLength = getUnicode().length(); + String[] pointCodes = new String[stringLength]; + String[] pointCodesHex = new String[stringLength]; + for (int offset = 0; offset < stringLength; ) { + final int codePoint = getUnicode().codePointAt(offset); + pointCodes[count] = String.format(Locale.getDefault(), "&#%d;", codePoint); + pointCodesHex[count++] = String.format("&#x%x;", codePoint); + offset += Character.charCount(codePoint); + } + this.htmlDec = stringJoin(pointCodes, count); + this.htmlHex = stringJoin(pointCodesHex, count); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } } - } - /** - * Method to replace String.join, since it was only introduced in java8 - * @param array the array to be concatenated - * @return concatenated String - */ - private String stringJoin(String[] array, int count){ - String joined = ""; - for(int i = 0; i < count; i++) - joined += array[i]; - return joined; - } - - /** - * Returns the description of the emoji - * - * @return the description - */ - public String getDescription() { - return this.description; - } - - /** - * Returns wether the emoji supports the Fitzpatrick modifiers or not - * - * @return true if the emoji supports the Fitzpatrick modifiers - */ - public boolean supportsFitzpatrick() { - return this.supportsFitzpatrick; - } - - /** - * Returns the aliases of the emoji - * - * @return the aliases (unmodifiable) - */ - public List getAliases() { - return this.aliases; - } - - /** - * Returns the tags of the emoji - * - * @return the tags (unmodifiable) - */ - public List getTags() { - return this.tags; - } - - /** - * Returns the unicode representation of the emoji - * - * @return the unicode representation - */ - public String getUnicode() { - return this.unicode; - } - - /** - * Returns the unicode representation of the emoji associated with the - * provided Fitzpatrick modifier.
- * If the modifier is null, then the result is similar to - * {@link Emoji#getUnicode()} - * - * @param fitzpatrick the fitzpatrick modifier or null - * - * @return the unicode representation - * @throws UnsupportedOperationException if the emoji doesn't support the - * Fitzpatrick modifiers - */ - public String getUnicode(Fitzpatrick fitzpatrick) { - if (!this.supportsFitzpatrick()) { - throw new UnsupportedOperationException( - "Cannot get the unicode with a fitzpatrick modifier, " + - "the emoji doesn't support fitzpatrick." - ); - } else if (fitzpatrick == null) { - return this.getUnicode(); + /** + * Method to replace String.join, since it was only introduced in java8 + * + * @param array + * the array to be concatenated + * @return concatenated String + */ + private String stringJoin(String[] array, int count) { + String joined = ""; + for (int i = 0; i < count; i++) + joined += array[i]; + return joined; } - return this.getUnicode() + fitzpatrick.unicode; - } - /** - * Returns the HTML decimal representation of the emoji - * - * @return the HTML decimal representation - */ - public String getHtmlDecimal() { - return this.htmlDec; - } + /** + * Returns the description of the emoji + * + * @return the description + */ + public String getDescription() { + return this.description; + } - /** - * @deprecated identical to {@link #getHtmlHexadecimal()} for - * backwards-compatibility. Use that instead. - * - * @return the HTML hexadecimal representation - */ - public String getHtmlHexidecimal() { - return this.getHtmlHexadecimal(); - } + /** + * Returns wether the emoji supports the Fitzpatrick modifiers or not + * + * @return true if the emoji supports the Fitzpatrick modifiers + */ + public boolean supportsFitzpatrick() { + return this.supportsFitzpatrick; + } - /** - * Returns the HTML hexadecimal representation of the emoji - * - * @return the HTML hexadecimal representation - */ - public String getHtmlHexadecimal() { - return this.htmlHex; - } + /** + * Returns the aliases of the emoji + * + * @return the aliases (unmodifiable) + */ + public List getAliases() { + return this.aliases; + } - @Override - public boolean equals(Object other) { - return !(other == null || !(other instanceof Emoji)) && - ((Emoji) other).getUnicode().equals(getUnicode()); - } + /** + * Returns the tags of the emoji + * + * @return the tags (unmodifiable) + */ + public List getTags() { + return this.tags; + } - @Override - public int hashCode() { - return unicode.hashCode(); - } + /** + * Returns the unicode representation of the emoji + * + * @return the unicode representation + */ + public String getUnicode() { + return this.unicode; + } - /** - * Returns the String representation of the Emoji object.
- *
- * Example:
- * Emoji { - * description='smiling face with open mouth and smiling eyes', - * supportsFitzpatrick=false, - * aliases=[smile], - * tags=[happy, joy, pleased], - * unicode='😄', - * htmlDec='&#128516;', - * htmlHex='&#x1f604;' - * } - * - * @return the string representation - */ - @Override - public String toString() { - return "Emoji{" + - "description='" + description + '\'' + - ", supportsFitzpatrick=" + supportsFitzpatrick + - ", aliases=" + aliases + - ", tags=" + tags + - ", unicode='" + unicode + '\'' + - ", htmlDec='" + htmlDec + '\'' + - ", htmlHex='" + htmlHex + '\'' + - '}'; - } + /** + * Returns the unicode representation of the emoji associated with the + * provided Fitzpatrick modifier.
+ * If the modifier is null, then the result is similar to + * {@link Emoji#getUnicode()} + * + * @param fitzpatrick + * the fitzpatrick modifier or null + * @return the unicode representation + * @throws UnsupportedOperationException + * if the emoji doesn't support the Fitzpatrick modifiers + */ + public String getUnicode(Fitzpatrick fitzpatrick) { + if (!this.supportsFitzpatrick()) { + throw new UnsupportedOperationException( + "Cannot get the unicode with a fitzpatrick modifier, " + + "the emoji doesn't support fitzpatrick." + ); + } else if (fitzpatrick == null) { + return this.getUnicode(); + } + return this.getUnicode() + fitzpatrick.unicode; + } + + /** + * Returns the HTML decimal representation of the emoji + * + * @return the HTML decimal representation + */ + public String getHtmlDecimal() { + return this.htmlDec; + } + + /** + * @return the HTML hexadecimal representation + * @deprecated identical to {@link #getHtmlHexadecimal()} for backwards-compatibility. Use that instead. + */ + public String getHtmlHexidecimal() { + return this.getHtmlHexadecimal(); + } + + /** + * Returns the HTML hexadecimal representation of the emoji + * + * @return the HTML hexadecimal representation + */ + public String getHtmlHexadecimal() { + return this.htmlHex; + } + + @Override + public boolean equals(Object other) { + return !(other == null || !(other instanceof Emoji)) && + ((Emoji) other).getUnicode().equals(getUnicode()); + } + + @Override + public int hashCode() { + return unicode.hashCode(); + } + + /** + * Returns the String representation of the Emoji object.
+ *
+ * Example:
+ * Emoji { + * description='smiling face with open mouth and smiling eyes', + * supportsFitzpatrick=false, + * aliases=[smile], + * tags=[happy, joy, pleased], + * unicode='😄', + * htmlDec='&#128516;', + * htmlHex='&#x1f604;' + * } + * + * @return the string representation + */ + @Override + public String toString() { + return "Emoji{" + + "description='" + description + '\'' + + ", supportsFitzpatrick=" + supportsFitzpatrick + + ", aliases=" + aliases + + ", tags=" + tags + + ", unicode='" + unicode + '\'' + + ", htmlDec='" + htmlDec + '\'' + + ", htmlHex='" + htmlHex + '\'' + + '}'; + } } diff --git a/app/src/main/java/com/fastaccess/provider/emoji/EmojiLoader.java b/app/src/main/java/com/fastaccess/provider/emoji/EmojiLoader.java index fd3000bf..5dd884df 100644 --- a/app/src/main/java/com/fastaccess/provider/emoji/EmojiLoader.java +++ b/app/src/main/java/com/fastaccess/provider/emoji/EmojiLoader.java @@ -16,10 +16,10 @@ import java.util.List; * * @author Vincent DURMONT [vdurmont@gmail.com] */ -public class EmojiLoader { +class EmojiLoader { private EmojiLoader() {} - public static List loadEmojis(InputStream stream) throws IOException { + static List loadEmojis(InputStream stream) throws IOException { try { JSONArray emojisJSON = new JSONArray(inputStreamToString(stream)); List emojis = new ArrayList(emojisJSON.length()); @@ -48,7 +48,7 @@ public class EmojiLoader { return sb.toString(); } - protected static Emoji buildEmojiFromJSON(JSONObject json) throws Exception { + private static Emoji buildEmojiFromJSON(JSONObject json) throws Exception { if (!json.has("emoji")) { return null; } diff --git a/app/src/main/java/com/fastaccess/provider/emoji/EmojiManager.java b/app/src/main/java/com/fastaccess/provider/emoji/EmojiManager.java index 1430afa3..c8283bfc 100644 --- a/app/src/main/java/com/fastaccess/provider/emoji/EmojiManager.java +++ b/app/src/main/java/com/fastaccess/provider/emoji/EmojiManager.java @@ -87,7 +87,7 @@ public class EmojiManager { return EMOJI_TRIE.getEmoji(unicode); } - public static Collection getAll() { + public static List getAll() { return ALL_EMOJIS; } diff --git a/app/src/main/java/com/fastaccess/provider/emoji/EmojiParser.java b/app/src/main/java/com/fastaccess/provider/emoji/EmojiParser.java index 8eebdf52..934b0ef5 100644 --- a/app/src/main/java/com/fastaccess/provider/emoji/EmojiParser.java +++ b/app/src/main/java/com/fastaccess/provider/emoji/EmojiParser.java @@ -52,32 +52,30 @@ public class EmojiParser { * * @return the string with the emojis replaced by their alias. */ - public static String parseToAliases( - String input, - final FitzpatrickAction fitzpatrickAction + private static String parseToAliases( + String input, + final FitzpatrickAction fitzpatrickAction ) { - EmojiTransformer emojiTransformer = new EmojiTransformer() { - public String transform(UnicodeCandidate unicodeCandidate) { - switch (fitzpatrickAction) { - default: - case PARSE: - if (unicodeCandidate.hasFitzpatrick()) { - return ":" + - unicodeCandidate.getEmoji().getAliases().get(0) + - "|" + - unicodeCandidate.getFitzpatrickType() + - ":"; - } - case REMOVE: + EmojiTransformer emojiTransformer = unicodeCandidate -> { + switch (fitzpatrickAction) { + default: + case PARSE: + if (unicodeCandidate.hasFitzpatrick()) { return ":" + - unicodeCandidate.getEmoji().getAliases().get(0) + - ":"; - case IGNORE: - return ":" + - unicodeCandidate.getEmoji().getAliases().get(0) + - ":" + - unicodeCandidate.getFitzpatrickUnicode(); - } + unicodeCandidate.getEmoji().getAliases().get(0) + + "|" + + unicodeCandidate.getFitzpatrickType() + + ":"; + } + case REMOVE: + return ":" + + unicodeCandidate.getEmoji().getAliases().get(0) + + ":"; + case IGNORE: + return ":" + + unicodeCandidate.getEmoji().getAliases().get(0) + + ":" + + unicodeCandidate.getFitzpatrickUnicode(); } }; @@ -132,7 +130,7 @@ public class EmojiParser { return result; } - protected static List getAliasCandidates(String input) { + private static List getAliasCandidates(String input) { List candidates = new ArrayList(); Matcher matcher = ALIAS_CANDIDATE_PATTERN.matcher(input); @@ -186,21 +184,19 @@ public class EmojiParser { * @return the string with the emojis replaced by their html decimal * representation. */ - public static String parseToHtmlDecimal( - String input, - final FitzpatrickAction fitzpatrickAction + private static String parseToHtmlDecimal( + String input, + final FitzpatrickAction fitzpatrickAction ) { - EmojiTransformer emojiTransformer = new EmojiTransformer() { - public String transform(UnicodeCandidate unicodeCandidate) { - switch (fitzpatrickAction) { - default: - case PARSE: - case REMOVE: - return unicodeCandidate.getEmoji().getHtmlDecimal(); - case IGNORE: - return unicodeCandidate.getEmoji().getHtmlDecimal() + - unicodeCandidate.getFitzpatrickUnicode(); - } + EmojiTransformer emojiTransformer = unicodeCandidate -> { + switch (fitzpatrickAction) { + default: + case PARSE: + case REMOVE: + return unicodeCandidate.getEmoji().getHtmlDecimal(); + case IGNORE: + return unicodeCandidate.getEmoji().getHtmlDecimal() + + unicodeCandidate.getFitzpatrickUnicode(); } }; @@ -241,21 +237,19 @@ public class EmojiParser { * @return the string with the emojis replaced by their html hex * representation. */ - public static String parseToHtmlHexadecimal( - String input, - final FitzpatrickAction fitzpatrickAction + private static String parseToHtmlHexadecimal( + String input, + final FitzpatrickAction fitzpatrickAction ) { - EmojiTransformer emojiTransformer = new EmojiTransformer() { - public String transform(UnicodeCandidate unicodeCandidate) { - switch (fitzpatrickAction) { - default: - case PARSE: - case REMOVE: - return unicodeCandidate.getEmoji().getHtmlHexadecimal(); - case IGNORE: - return unicodeCandidate.getEmoji().getHtmlHexadecimal() + - unicodeCandidate.getFitzpatrickUnicode(); - } + EmojiTransformer emojiTransformer = unicodeCandidate -> { + switch (fitzpatrickAction) { + default: + case PARSE: + case REMOVE: + return unicodeCandidate.getEmoji().getHtmlHexadecimal(); + case IGNORE: + return unicodeCandidate.getEmoji().getHtmlHexadecimal() + + unicodeCandidate.getFitzpatrickUnicode(); } }; @@ -270,11 +264,7 @@ public class EmojiParser { * @return the string without any emoji */ public static String removeAllEmojis(String str) { - EmojiTransformer emojiTransformer = new EmojiTransformer() { - public String transform(UnicodeCandidate unicodeCandidate) { - return ""; - } - }; + EmojiTransformer emojiTransformer = unicodeCandidate -> ""; return parseFromUnicode(str, emojiTransformer); } @@ -292,14 +282,12 @@ public class EmojiParser { String str, final Collection emojisToRemove ) { - EmojiTransformer emojiTransformer = new EmojiTransformer() { - public String transform(UnicodeCandidate unicodeCandidate) { - if (!emojisToRemove.contains(unicodeCandidate.getEmoji())) { - return unicodeCandidate.getEmoji().getUnicode() + - unicodeCandidate.getFitzpatrickUnicode(); - } - return ""; + EmojiTransformer emojiTransformer = unicodeCandidate -> { + if (!emojisToRemove.contains(unicodeCandidate.getEmoji())) { + return unicodeCandidate.getEmoji().getUnicode() + + unicodeCandidate.getFitzpatrickUnicode(); } + return ""; }; return parseFromUnicode(str, emojiTransformer); @@ -317,14 +305,12 @@ public class EmojiParser { String str, final Collection emojisToKeep ) { - EmojiTransformer emojiTransformer = new EmojiTransformer() { - public String transform(UnicodeCandidate unicodeCandidate) { - if (emojisToKeep.contains(unicodeCandidate.getEmoji())) { - return unicodeCandidate.getEmoji().getUnicode() + - unicodeCandidate.getFitzpatrickUnicode(); - } - return ""; + EmojiTransformer emojiTransformer = unicodeCandidate -> { + if (emojisToKeep.contains(unicodeCandidate.getEmoji())) { + return unicodeCandidate.getEmoji().getUnicode() + + unicodeCandidate.getFitzpatrickUnicode(); } + return ""; }; return parseFromUnicode(str, emojiTransformer); @@ -340,9 +326,9 @@ public class EmojiParser { * * @return input string with all emojis transformed */ - public static String parseFromUnicode( - String input, - EmojiTransformer transformer + private static String parseFromUnicode( + String input, + EmojiTransformer transformer ) { int prev = 0; StringBuilder sb = new StringBuilder(); @@ -378,7 +364,7 @@ public class EmojiParser { * @param input String to find all unicode emojis in * @return List of UnicodeCandidates for each unicode emote in text */ - protected static List getUnicodeCandidates(String input) { + private static List getUnicodeCandidates(String input) { char[] inputCharArray = input.toCharArray(); List candidates = new ArrayList(); for (int i = 0; i < input.length(); i++) { @@ -417,7 +403,7 @@ public class EmojiParser { * @return the end index of the unicode emoji starting at startPos. -1 if not * found */ - protected static int getEmojiEndPos(char[] text, int startPos) { + private static int getEmojiEndPos(char[] text, int startPos) { int best = -1; for (int j = startPos + 1; j <= text.length; j++) { EmojiTrie.Matches status = EmojiManager.isEmoji(Arrays.copyOfRange( @@ -482,7 +468,7 @@ public class EmojiParser { } - protected static class AliasCandidate { + static class AliasCandidate { public final String fullString; public final String alias; public final Fitzpatrick fitzpatrick; diff --git a/app/src/main/java/com/fastaccess/provider/fabric/FabricProvider.java b/app/src/main/java/com/fastaccess/provider/fabric/FabricProvider.java new file mode 100644 index 00000000..6c5e7275 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/fabric/FabricProvider.java @@ -0,0 +1,15 @@ +package com.fastaccess.provider.fabric; + +import android.content.Context; +import android.support.annotation.NonNull; + +/** + * Created by kosh on 14/08/2017. + */ + +public class FabricProvider { + + public static void initFabric(@NonNull Context context) {}//DO NOTHING IN DEBUG + + public static void logPurchase(@NonNull String productKey) {}//DO NOTHING IN DEBUG +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt b/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt new file mode 100644 index 00000000..d8459152 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt @@ -0,0 +1,31 @@ +package com.fastaccess.provider.markdown + +import java.util.* + +/** + * Created by kosh on 11/08/2017. + */ +class CachedComments private constructor() { + + val map = WeakHashMap() + + fun put(repo: String?, login: String?, number: Any?, comment: CharSequence) { + map.put("$repo/$login/$number", comment) + } + + fun get(repo: String?, login: String?, number: Any?): CharSequence? { + return map["$repo/$login/$number"] + } + + fun clear() { + map.clear() + } + + private object Holder { + val INSTANCE = CachedComments() + } + + companion object { + val instance: CachedComments by lazy { Holder.INSTANCE } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java b/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java index 42c0fe70..a97ccd85 100644 --- a/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java +++ b/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java @@ -3,18 +3,31 @@ package com.fastaccess.provider.markdown; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.Html; +import android.view.ViewTreeObserver; import android.webkit.MimeTypeMap; import android.widget.EditText; import android.widget.TextView; import com.annimon.stream.IntStream; import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.Logger; +import com.fastaccess.provider.markdown.extension.emoji.EmojiExtension; +import com.fastaccess.provider.markdown.extension.mention.MentionExtension; import com.fastaccess.provider.timeline.HtmlHelper; +import org.commonmark.Extension; +import org.commonmark.ext.autolink.AutolinkExtension; +import org.commonmark.ext.front.matter.YamlFrontMatterExtension; +import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension; +import org.commonmark.ext.gfm.tables.TablesExtension; +import org.commonmark.ext.ins.InsExtension; import org.commonmark.node.Node; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; +import java.util.Arrays; +import java.util.List; + /** * Created by Kosh on 24 Nov 2016, 7:43 PM */ @@ -35,12 +48,42 @@ public class MarkDownProvider { public static void setMdText(@NonNull TextView textView, String markdown) { if (!InputHelper.isEmpty(markdown)) { - Parser parser = Parser.builder().build(); - Node node = parser.parse(markdown); - HtmlHelper.htmlIntoTextView(textView, HtmlRenderer.builder().build().render(node)); + int width = textView.getMeasuredWidth(); + if (width > 0) { + render(textView, markdown, width); + } else { + textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override public void onGlobalLayout() { + textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + render(textView, markdown, textView.getMeasuredWidth()); + } + }); + } } } + protected static void render(@NonNull TextView textView, String markdown, int width) { + List extensions = Arrays.asList( + StrikethroughExtension.create(), + AutolinkExtension.create(), + TablesExtension.create(), + InsExtension.create(), + EmojiExtension.create(), + MentionExtension.create(), + YamlFrontMatterExtension.create()); + Parser parser = Parser.builder() + .extensions(extensions) + .build(); + Node node = parser.parse(markdown); + String rendered = HtmlRenderer + .builder() + .extensions(extensions) + .build() + .render(node); + Logger.e(rendered); + HtmlHelper.htmlIntoTextView(textView, rendered, (width - (textView.getPaddingStart() + textView.getPaddingEnd()))); + } + public static void stripMdText(@NonNull TextView textView, String markdown) { if (!InputHelper.isEmpty(markdown)) { Parser parser = Parser.builder().build(); @@ -49,7 +92,7 @@ public class MarkDownProvider { } } - private static String stripHtml(String html) { + public static String stripHtml(String html) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY).toString(); } else { @@ -125,7 +168,7 @@ public class MarkDownProvider { int selectionStart = editText.getSelectionStart(); int selectionEnd = editText.getSelectionEnd(); String substring = source.substring(selectionStart, selectionEnd); - String result = "__" + substring + "__ "; + String result = "**" + substring + "** "; editText.getText().replace(selectionStart, selectionEnd, result); editText.setSelection(result.length() + selectionStart - 3); @@ -151,6 +194,17 @@ public class MarkDownProvider { } } + public static void addInlinleCode(@NonNull EditText editText) { + String source = editText.getText().toString(); + int selectionStart = editText.getSelectionStart(); + int selectionEnd = editText.getSelectionEnd(); + String substring = source.substring(selectionStart, selectionEnd); + String result = "`" + substring + "` "; + editText.getText().replace(selectionStart, selectionEnd, result); + editText.setSelection(result.length() + selectionStart - 2); + + } + public static void addStrikeThrough(@NonNull EditText editText) { String source = editText.getText().toString(); int selectionStart = editText.getSelectionStart(); diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/Emoji.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/Emoji.java new file mode 100644 index 00000000..7af55f48 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/Emoji.java @@ -0,0 +1,21 @@ +package com.fastaccess.provider.markdown.extension.emoji; + +import org.commonmark.node.CustomNode; +import org.commonmark.node.Delimited; + +/** + * Created by kosh on 20/08/2017. + */ + +public class Emoji extends CustomNode implements Delimited { + + private static final String DELIMITER = ":"; + + @Override public String getOpeningDelimiter() { + return DELIMITER; + } + + @Override public String getClosingDelimiter() { + return DELIMITER; + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/EmojiExtension.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/EmojiExtension.java new file mode 100644 index 00000000..1414f486 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/EmojiExtension.java @@ -0,0 +1,28 @@ +package com.fastaccess.provider.markdown.extension.emoji; + +import com.fastaccess.provider.markdown.extension.emoji.internal.EmojiDelimiterProcessor; +import com.fastaccess.provider.markdown.extension.emoji.internal.EmojiNodeRenderer; + +import org.commonmark.Extension; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; + +/** + * Created by kosh on 20/08/2017. + */ + +public class EmojiExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension { + private EmojiExtension() {} + + public static Extension create() { + return new EmojiExtension(); + } + + @Override public void extend(Parser.Builder parserBuilder) { + parserBuilder.customDelimiterProcessor(new EmojiDelimiterProcessor()); + } + + @Override public void extend(HtmlRenderer.Builder rendererBuilder) { + rendererBuilder.nodeRendererFactory(EmojiNodeRenderer::new); + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/internal/EmojiDelimiterProcessor.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/internal/EmojiDelimiterProcessor.java new file mode 100644 index 00000000..2a80257d --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/internal/EmojiDelimiterProcessor.java @@ -0,0 +1,42 @@ +package com.fastaccess.provider.markdown.extension.emoji.internal; + +import com.fastaccess.provider.markdown.extension.emoji.Emoji; + +import org.commonmark.node.Node; +import org.commonmark.node.Text; +import org.commonmark.parser.delimiter.DelimiterProcessor; +import org.commonmark.parser.delimiter.DelimiterRun; + +public class EmojiDelimiterProcessor implements DelimiterProcessor { + + @Override public char getOpeningCharacter() { + return ':'; + } + + @Override public char getClosingCharacter() { + return ':'; + } + + @Override public int getMinLength() { + return 1; + } + + @Override public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) { + if (opener.length() >= 1 && closer.length() >= 1) { + return 1; + } else { + return 0; + } + } + + @Override public void process(Text opener, Text closer, int delimiterCount) { + Node emoji = new Emoji(); + Node tmp = opener.getNext(); + while (tmp != null && tmp != closer) { + Node next = tmp.getNext(); + emoji.appendChild(tmp); + tmp = next; + } + opener.insertAfter(emoji); + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/internal/EmojiNodeRenderer.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/internal/EmojiNodeRenderer.java new file mode 100644 index 00000000..bbef8b81 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/emoji/internal/EmojiNodeRenderer.java @@ -0,0 +1,41 @@ +package com.fastaccess.provider.markdown.extension.emoji.internal; + +import org.commonmark.node.Node; +import org.commonmark.renderer.NodeRenderer; +import org.commonmark.renderer.html.HtmlNodeRendererContext; +import org.commonmark.renderer.html.HtmlWriter; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +public class EmojiNodeRenderer implements NodeRenderer { + + private final HtmlNodeRendererContext context; + private final HtmlWriter html; + + public EmojiNodeRenderer(HtmlNodeRendererContext context) { + this.context = context; + this.html = context.getWriter(); + } + + @Override public Set> getNodeTypes() { + return Collections.singleton(com.fastaccess.provider.markdown.extension.emoji.Emoji.class); + } + + @Override public void render(Node node) { + Map attributes = context.extendAttributes(node, "emoji", Collections.emptyMap()); + html.tag("emoji", attributes); + renderChildren(node); + html.tag("/emoji"); + } + + private void renderChildren(Node parent) { + Node node = parent.getFirstChild(); + while (node != null) { + Node next = node.getNext(); + context.render(node); + node = next; + } + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/Mention.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/Mention.java new file mode 100644 index 00000000..c2d148c7 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/Mention.java @@ -0,0 +1,21 @@ +package com.fastaccess.provider.markdown.extension.mention; + +import org.commonmark.node.CustomNode; +import org.commonmark.node.Delimited; + +/** + * Created by kosh on 20/08/2017. + */ + +public class Mention extends CustomNode implements Delimited { + + private static final String DELIMITER = "@"; + + @Override public String getOpeningDelimiter() { + return DELIMITER; + } + + @Override public String getClosingDelimiter() { + return " "; + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/MentionExtension.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/MentionExtension.java new file mode 100644 index 00000000..5a8fa103 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/MentionExtension.java @@ -0,0 +1,28 @@ +package com.fastaccess.provider.markdown.extension.mention; + +import com.fastaccess.provider.markdown.extension.mention.internal.MentionDelimiterProcessor; +import com.fastaccess.provider.markdown.extension.mention.internal.MentionNodeRenderer; + +import org.commonmark.Extension; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; + +/** + * Created by kosh on 20/08/2017. + */ + +public class MentionExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension { + private MentionExtension() {} + + public static Extension create() { + return new MentionExtension(); + } + + @Override public void extend(Parser.Builder parserBuilder) { + parserBuilder.customDelimiterProcessor(new MentionDelimiterProcessor()); + } + + @Override public void extend(HtmlRenderer.Builder rendererBuilder) { + rendererBuilder.nodeRendererFactory(MentionNodeRenderer::new); + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/internal/MentionDelimiterProcessor.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/internal/MentionDelimiterProcessor.java new file mode 100644 index 00000000..5b3f6d0d --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/internal/MentionDelimiterProcessor.java @@ -0,0 +1,42 @@ +package com.fastaccess.provider.markdown.extension.mention.internal; + +import com.fastaccess.provider.markdown.extension.mention.Mention; + +import org.commonmark.node.Node; +import org.commonmark.node.Text; +import org.commonmark.parser.delimiter.DelimiterProcessor; +import org.commonmark.parser.delimiter.DelimiterRun; + +public class MentionDelimiterProcessor implements DelimiterProcessor { + + @Override public char getOpeningCharacter() { + return '@'; + } + + @Override public char getClosingCharacter() { + return ' '; + } + + @Override public int getMinLength() { + return 1; + } + + @Override public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) { + if (opener.length() >= 1 && closer.length() >= 1) { + return 1; + } else { + return 0; + } + } + + @Override public void process(Text opener, Text closer, int delimiterCount) { + Node mention = new Mention(); + Node tmp = opener.getNext(); + while (tmp != null && tmp != closer) { + Node next = tmp.getNext(); + mention.appendChild(tmp); + tmp = next; + } + opener.insertAfter(mention); + } +} diff --git a/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/internal/MentionNodeRenderer.java b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/internal/MentionNodeRenderer.java new file mode 100644 index 00000000..c09fe0fd --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/markdown/extension/mention/internal/MentionNodeRenderer.java @@ -0,0 +1,43 @@ +package com.fastaccess.provider.markdown.extension.mention.internal; + +import com.fastaccess.provider.markdown.extension.mention.Mention; + +import org.commonmark.node.Node; +import org.commonmark.renderer.NodeRenderer; +import org.commonmark.renderer.html.HtmlNodeRendererContext; +import org.commonmark.renderer.html.HtmlWriter; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +public class MentionNodeRenderer implements NodeRenderer { + + private final HtmlNodeRendererContext context; + private final HtmlWriter html; + + public MentionNodeRenderer(HtmlNodeRendererContext context) { + this.context = context; + this.html = context.getWriter(); + } + + @Override public Set> getNodeTypes() { + return Collections.singleton(Mention.class); + } + + @Override public void render(Node node) { + Map attributes = context.extendAttributes(node, "mention", Collections.emptyMap()); + html.tag("mention", attributes); + renderChildren(node); + html.tag("/mention"); + } + + private void renderChildren(Node parent) { + Node node = parent.getFirstChild(); + while (node != null) { + Node next = node.getNext(); + context.render(node); + node = next; + } + } +} diff --git a/app/src/main/java/com/fastaccess/provider/rest/RestProvider.java b/app/src/main/java/com/fastaccess/provider/rest/RestProvider.java index ce9288a8..68633490 100644 --- a/app/src/main/java/com/fastaccess/provider/rest/RestProvider.java +++ b/app/src/main/java/com/fastaccess/provider/rest/RestProvider.java @@ -58,10 +58,11 @@ public class RestProvider { .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC) .setDateFormat("yyyy-MM-dd HH:mm:ss") + .disableHtmlEscaping() .setPrettyPrinting() .create(); - private static OkHttpClient provideOkHttpClient() { + public static OkHttpClient provideOkHttpClient() { if (okHttpClient == null) { OkHttpClient.Builder client = new OkHttpClient.Builder(); if (BuildConfig.DEBUG) { diff --git a/app/src/main/java/com/fastaccess/provider/rest/interceptors/PaginationInterceptor.java b/app/src/main/java/com/fastaccess/provider/rest/interceptors/PaginationInterceptor.java index e49fdcbd..4875f0c8 100644 --- a/app/src/main/java/com/fastaccess/provider/rest/interceptors/PaginationInterceptor.java +++ b/app/src/main/java/com/fastaccess/provider/rest/interceptors/PaginationInterceptor.java @@ -7,14 +7,24 @@ import com.fastaccess.helper.InputHelper; import java.io.IOException; +import okhttp3.Headers; import okhttp3.Interceptor; +import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; public class PaginationInterceptor implements Interceptor { @Override public Response intercept(@NonNull Chain chain) throws IOException { - Response response = chain.proceed(chain.request()); + Request request = chain.request(); + Response response = chain.proceed(request); + Headers headers = chain.request().headers(); + if (headers != null) { + if ((headers.values("Accept").contains("application/vnd.github.html") || + headers.values("Accept").contains("application/vnd.github.VERSION.raw"))) { + return response;//return them as they are. + } + } if (response.isSuccessful()) { if (response.peekBody(1).string().equals("[")) { String json = "{"; diff --git a/app/src/main/java/com/fastaccess/provider/rest/loadmore/OnLoadMore.java b/app/src/main/java/com/fastaccess/provider/rest/loadmore/OnLoadMore.java index 8e9de3bb..f0d77da7 100644 --- a/app/src/main/java/com/fastaccess/provider/rest/loadmore/OnLoadMore.java +++ b/app/src/main/java/com/fastaccess/provider/rest/loadmore/OnLoadMore.java @@ -29,10 +29,11 @@ public class OnLoadMore

extends InfiniteScroll { return parameter; } - @Override public void onLoadMore(int page, int totalItemsCount) { + @Override public boolean onLoadMore(int page, int totalItemsCount) { if (presenter != null) { presenter.setPreviousTotal(totalItemsCount); - presenter.onCallApi(page + 1, parameter); + return presenter.onCallApi(page + 1, parameter); } + return false; } } \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/provider/scheme/SchemeParser.java b/app/src/main/java/com/fastaccess/provider/scheme/SchemeParser.java index 571afcf8..5e60502f 100644 --- a/app/src/main/java/com/fastaccess/provider/scheme/SchemeParser.java +++ b/app/src/main/java/com/fastaccess/provider/scheme/SchemeParser.java @@ -31,6 +31,7 @@ import com.fastaccess.ui.modules.repos.issues.create.CreateIssueActivity; import com.fastaccess.ui.modules.repos.issues.issue.details.IssuePagerActivity; import com.fastaccess.ui.modules.repos.pull_requests.pull_request.details.PullRequestPagerActivity; import com.fastaccess.ui.modules.repos.wiki.WikiActivity; +import com.fastaccess.ui.modules.search.SearchActivity; import com.fastaccess.ui.modules.trending.TrendingActivity; import com.fastaccess.ui.modules.user.UserPagerActivity; @@ -338,6 +339,9 @@ public class SchemeParser { } else if (segments != null && !segments.isEmpty() && segments.size() > 1 && segments.get(0).equalsIgnoreCase("orgs")) { if ("invitation".equalsIgnoreCase(uri.getLastPathSegment())) { return null; + } else if ("search".equalsIgnoreCase(uri.getLastPathSegment())) { + String query = uri.getQueryParameter("q"); + return SearchActivity.getIntent(context, query); } else { return UserPagerActivity.createIntent(context, segments.get(1), true); } diff --git a/app/src/main/java/com/fastaccess/provider/tasks/notification/NotificationSchedulerJobTask.java b/app/src/main/java/com/fastaccess/provider/tasks/notification/NotificationSchedulerJobTask.java index 3d1eccbf..aea0a71c 100644 --- a/app/src/main/java/com/fastaccess/provider/tasks/notification/NotificationSchedulerJobTask.java +++ b/app/src/main/java/com/fastaccess/provider/tasks/notification/NotificationSchedulerJobTask.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.media.AudioManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; @@ -91,6 +92,7 @@ public class NotificationSchedulerJobTask extends JobService { public static void scheduleJob(@NonNull Context context, int duration, boolean cancel) { if (AppHelper.isGoogleAvailable(context)) { FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context)); + dispatcher.cancel(SINGLE_JOB_ID); if (cancel) dispatcher.cancel(JOB_ID); if (duration == -1) { dispatcher.cancel(JOB_ID); @@ -254,7 +256,7 @@ public class NotificationSchedulerJobTask extends JobService { new Intent(getApplicationContext(), NotificationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); return getNotification(thread.getSubject().getTitle(), thread.getRepository().getFullName()) .setDefaults(PrefGetter.isNotificationSoundEnabled() ? NotificationCompat.DEFAULT_ALL : 0) - .setSound(PrefGetter.getNotificationSound()) + .setSound(PrefGetter.getNotificationSound(), AudioManager.STREAM_NOTIFICATION) .setContentIntent(toNotificationActivity ? pendingIntent : getPendingIntent(thread.getId(), thread.getSubject().getUrl())) .addAction(R.drawable.ic_github, getString(R.string.open), getPendingIntent(thread.getId(), thread .getSubject().getUrl())) diff --git a/app/src/main/java/com/fastaccess/provider/theme/ThemeEngine.kt b/app/src/main/java/com/fastaccess/provider/theme/ThemeEngine.kt index dfdfc238..81477840 100644 --- a/app/src/main/java/com/fastaccess/provider/theme/ThemeEngine.kt +++ b/app/src/main/java/com/fastaccess/provider/theme/ThemeEngine.kt @@ -57,7 +57,7 @@ object ThemeEngine { setTaskDescription(activity) } - @StyleRes fun getTheme(themeMode: Int, themeColor: Int): Int { + @StyleRes private fun getTheme(themeMode: Int, themeColor: Int): Int { Logger.e(themeMode, themeColor) // I wish if I could simplify this :'( too many cases for the love of god. when (themeMode) { @@ -156,7 +156,7 @@ object ThemeEngine { return R.style.ThemeLight } - @StyleRes fun getDialogTheme(themeMode: Int, themeColor: Int): Int { + @StyleRes private fun getDialogTheme(themeMode: Int, themeColor: Int): Int { when (themeMode) { PrefGetter.LIGHT -> when (themeColor) { PrefGetter.RED -> return R.style.DialogThemeLight_Red diff --git a/app/src/main/java/com/fastaccess/provider/timeline/CommentsHelper.java b/app/src/main/java/com/fastaccess/provider/timeline/CommentsHelper.java index c8be02e4..3814968b 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/CommentsHelper.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/CommentsHelper.java @@ -62,7 +62,7 @@ public class CommentsHelper { } } - public static String getEmojiByUnicode(int unicode) { + private static String getEmojiByUnicode(int unicode) { return new String(Character.toChars(unicode)); } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/HtmlHelper.java b/app/src/main/java/com/fastaccess/provider/timeline/HtmlHelper.java index 658a2724..7de7c038 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/HtmlHelper.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/HtmlHelper.java @@ -1,21 +1,20 @@ package com.fastaccess.provider.timeline; + import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.graphics.Color; -import android.graphics.Point; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.view.HapticFeedbackConstants; -import android.view.WindowManager; +import android.view.ViewTreeObserver; import android.widget.PopupMenu; import android.widget.TextView; -import com.fastaccess.App; import com.fastaccess.R; import com.fastaccess.helper.PrefGetter; import com.fastaccess.helper.ViewHelper; @@ -23,6 +22,7 @@ import com.fastaccess.provider.scheme.SchemeParser; import com.fastaccess.provider.timeline.handler.BetterLinkMovementExtended; import com.fastaccess.provider.timeline.handler.DrawableHandler; import com.fastaccess.provider.timeline.handler.EmojiHandler; +import com.fastaccess.provider.timeline.handler.HrHandler; import com.fastaccess.provider.timeline.handler.ItalicHandler; import com.fastaccess.provider.timeline.handler.LinkHandler; import com.fastaccess.provider.timeline.handler.ListsHandler; @@ -45,9 +45,18 @@ import net.nightwhistler.htmlspanner.handlers.BoldHandler; public class HtmlHelper { - public static void htmlIntoTextView(@NonNull TextView textView, @NonNull String html) { + public static void htmlIntoTextView(@NonNull TextView textView, @NonNull String html, int width) { registerClickEvent(textView); - textView.setText(initHtml(textView).fromHtml(format(html).toString())); + if (textView.getMeasuredWidth() > 0) { + textView.setText(initHtml(textView, getActualWidth(textView)).fromHtml(format(html).toString())); + } else { + textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override public void onGlobalLayout() { + textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + textView.setText(initHtml(textView, getActualWidth(textView)).fromHtml(format(html).toString())); + } + }); + } } private static void registerClickEvent(@NonNull TextView textView) { @@ -82,7 +91,11 @@ public class HtmlHelper { }); } - private static HtmlSpanner initHtml(@NonNull TextView textView) { + private static int getActualWidth(TextView textView) { + return textView.getMeasuredWidth() - (convertDpToPx(textView.getContext(), 16)); + } + + private static HtmlSpanner initHtml(@NonNull TextView textView, int width) { @PrefGetter.ThemeType int theme = PrefGetter.getThemeType(); @ColorInt int windowBackground = getWindowBackground(theme); Drawable checked = ContextCompat.getDrawable(textView.getContext(), R.drawable.ic_checkbox_small); @@ -108,13 +121,12 @@ public class HtmlHelper { mySpanner.registerHandler("sub", new SubScriptHandler()); mySpanner.registerHandler("sup", new SuperScriptHandler()); mySpanner.registerHandler("a", new LinkHandler()); + mySpanner.registerHandler("hr", new HrHandler(windowBackground, width, false)); + mySpanner.registerHandler("emoji", new EmojiHandler()); + mySpanner.registerHandler("mention", new LinkHandler()); TableHandler tableHandler = new TableHandler(); tableHandler.setTextColor(ViewHelper.generateTextColor(windowBackground)); - WindowManager windowManager = (WindowManager) App.getInstance().getSystemService(Context.WINDOW_SERVICE); - Point point = new Point(); - windowManager.getDefaultDisplay().getRealSize(point); - tableHandler.setTableWidth((int) (point.x / 1.2)); - tableHandler.setTextSize(18.0F); + tableHandler.setTableWidth(width); mySpanner.registerHandler("table", tableHandler); return mySpanner; } @@ -144,10 +156,6 @@ public class HtmlHelper { private static final String SIGNATURE_END = ""; - private static final String EMAIL_START = "

"; - - private static final String EMAIL_END = "
"; - private static final String HIDDEN_REPLY_START = "
"; private static final String HIDDEN_REPLY_END = "
"; @@ -206,4 +214,9 @@ public class HtmlHelper { length = input.length(); } } + + private static int convertDpToPx(Context context, float dp) { + return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f); + } + } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/TimelineConverter.kt b/app/src/main/java/com/fastaccess/provider/timeline/TimelineConverter.kt new file mode 100644 index 00000000..0a6dbaf9 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/timeline/TimelineConverter.kt @@ -0,0 +1,135 @@ +package com.fastaccess.provider.timeline + +import com.fastaccess.data.dao.* +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.data.dao.timeline.GenericEvent +import com.fastaccess.data.dao.timeline.PullRequestCommitModel +import com.fastaccess.data.dao.types.IssueEventType +import com.fastaccess.helper.InputHelper +import com.fastaccess.helper.Logger +import com.fastaccess.provider.rest.RestProvider +import com.google.gson.Gson +import com.google.gson.JsonObject +import io.reactivex.Observable + +/** + * Created by kosh on 26/07/2017. + */ + +object TimelineConverter { + + fun convert(jsonObjects: List?): Observable { + if (jsonObjects == null) return Observable.empty() + val gson = RestProvider.gson + return Observable.fromIterable(jsonObjects) + .map { jsonObject -> + val event = jsonObject.get("event").asString + val timeline = TimelineModel() + if (!InputHelper.isEmpty(event)) { + val type = IssueEventType.getType(event) + timeline.event = type + if (type != null) { + if (type == IssueEventType.commented) { + timeline.comment = getComment(jsonObject, gson) + } else { + timeline.genericEvent = getGenericEvent(jsonObject, gson) + } + } + } else { + timeline.genericEvent = getGenericEvent(jsonObject, gson) + } + timeline + } + .filter { filterEvents(it.event) } + } + + fun convert(jsonObjects: List?, comments: Pageable?): List { + val list = arrayListOf() + if (jsonObjects == null) return list + val gson = RestProvider.gson + Logger.e(comments?.items?.size) + jsonObjects.onEach { jsonObject -> + val event = jsonObject.get("event").asString + val timeline = TimelineModel() + if (!InputHelper.isEmpty(event)) { + val type = IssueEventType.getType(event) + timeline.event = type + if (type != null) { + if (type == IssueEventType.commented) { + timeline.comment = getComment(jsonObject, gson) + list.add(timeline) + } else if (type == IssueEventType.commit_commented) { + val commit = getCommit(jsonObject, gson) + if (commit != null) { + val comment = commit.comments?.firstOrNull() + comment?.let { + commit.path = it.path + commit.position = it.position + commit.line = it.line + commit.login = it.user?.login + } + timeline.commit = commit + list.add(timeline) + } + } else if (type == IssueEventType.reviewed || type == IssueEventType + .changes_requested) { + val review = getReview(jsonObject, gson) + if (review != null) { + timeline.review = review + list.add(timeline) + val reviewsList = arrayListOf() + comments?.items?.filter { it.pullRequestReviewId == review.id } + ?.onEach { + val grouped = GroupedReviewModel() + grouped.diffText = it.diffHunk + grouped.path = it.path + grouped.position = it.position + grouped.comments = arrayListOf(it) + grouped.id = it.id + val groupTimeline = TimelineModel() + groupTimeline.event = IssueEventType.GROUPED + groupTimeline.groupedReviewModel = grouped + reviewsList.add(groupTimeline) + } + comments?.items?.filter { it.pullRequestReviewId != review.id }?.onEach { + reviewsList.onEach { reviews -> + if (it.path == reviews.groupedReviewModel.path && it.position == reviews.groupedReviewModel.position) { + reviews.groupedReviewModel.comments.add(it) + } + } + } + list.addAll(reviewsList) + } + } else { + timeline.genericEvent = getGenericEvent(jsonObject, gson) + list.add(timeline) + } + } + } else { + timeline.genericEvent = getGenericEvent(jsonObject, gson) + list.add(timeline) + } + } + return list.filter({filterEvents(it.event)}) + } + + private fun getCommit(jsonObject: JsonObject, gson: Gson): PullRequestCommitModel? { + return gson.fromJson(jsonObject, PullRequestCommitModel::class.java) + } + + private fun getGenericEvent(jsonObject: JsonObject, gson: Gson): GenericEvent { + return gson.fromJson(jsonObject, GenericEvent::class.java) + } + + private fun getComment(jsonObject: JsonObject, gson: Gson): Comment { + return gson.fromJson(jsonObject, Comment::class.java) + } + + private fun filterEvents(type: IssueEventType?): Boolean { + return type != null && type != IssueEventType.subscribed && type != IssueEventType.unsubscribed && type != IssueEventType.mentioned + } + + private fun getReview(jsonObject: JsonObject, gson: Gson): ReviewModel? { + return gson.fromJson(jsonObject, ReviewModel::class.java) + } +} diff --git a/app/src/main/java/com/fastaccess/provider/timeline/TimelineProvider.java b/app/src/main/java/com/fastaccess/provider/timeline/TimelineProvider.java index 7f295e82..9b93c6cc 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/TimelineProvider.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/TimelineProvider.java @@ -8,14 +8,14 @@ import android.text.style.BackgroundColorSpan; import com.fastaccess.R; import com.fastaccess.data.dao.LabelModel; -import com.fastaccess.data.dao.model.IssueEvent; import com.fastaccess.data.dao.model.User; +import com.fastaccess.data.dao.timeline.GenericEvent; +import com.fastaccess.data.dao.timeline.SourceModel; import com.fastaccess.data.dao.types.IssueEventType; import com.fastaccess.helper.InputHelper; import com.fastaccess.helper.ParseDateFormat; import com.fastaccess.helper.PrefGetter; import com.fastaccess.helper.ViewHelper; -import com.fastaccess.ui.widgets.LabelSpan; import com.fastaccess.ui.widgets.SpannableBuilder; import com.zzhoujay.markdown.style.CodeSpan; @@ -27,39 +27,45 @@ import java.util.Date; public class TimelineProvider { - @NonNull public static SpannableBuilder getStyledEvents(@NonNull IssueEvent issueEventModel, @NonNull Context context, boolean isMerged) { + @NonNull public static SpannableBuilder getStyledEvents(@NonNull GenericEvent issueEventModel, + @NonNull Context context, boolean isMerged) { IssueEventType event = issueEventModel.getEvent(); SpannableBuilder spannableBuilder = SpannableBuilder.builder(); + Date date = issueEventModel.getCreatedAt() != null + ? issueEventModel.getCreatedAt() + : issueEventModel.getAuthor() != null + ? issueEventModel.getAuthor().getDate() : null; if (event != null) { String to = context.getString(R.string.to); String from = context.getString(R.string.from); String thisString = context.getString(R.string.this_value); String in = context.getString(R.string.in_value); if (event == IssueEventType.labeled || event == IssueEventType.unlabeled) { - if (issueEventModel.getAssignee() != null && issueEventModel.getAssigner() != null) { - spannableBuilder.bold(issueEventModel.getAssigner().getLogin()); - } else if (issueEventModel.getActor() != null) { - spannableBuilder.bold(issueEventModel.getActor().getLogin()); - } + spannableBuilder.bold(issueEventModel.getActor().getLogin()); spannableBuilder.append(" ").append(event.name().replaceAll("_", " ")); LabelModel labelModel = issueEventModel.getLabel(); int color = Color.parseColor("#" + labelModel.getColor()); spannableBuilder.append(" ").append(" " + labelModel.getName() + " ", new CodeSpan(color, ViewHelper.generateTextColor(color), 5)); spannableBuilder.append(" ").append(getDate(issueEventModel.getCreatedAt())); + } else if (event == IssueEventType.committed) { + spannableBuilder.append(issueEventModel.getMessage().replaceAll("\n", " ")) + .append(" ") + .url(substring(issueEventModel.getSha())); } else { User user = null; if (issueEventModel.getAssignee() != null && issueEventModel.getAssigner() != null) { user = issueEventModel.getAssigner(); } else if (issueEventModel.getActor() != null) { user = issueEventModel.getActor(); + } else if (issueEventModel.getAuthor() != null) { + user = issueEventModel.getAuthor(); } if (user != null) { spannableBuilder.bold(user.getLogin()); } - if ((event == IssueEventType.review_requested || (event == IssueEventType.review_dismissed || event == IssueEventType.review_request_removed)) && user != null) { - appendReviews(issueEventModel, event, spannableBuilder, from, user); + appendReviews(issueEventModel, event, spannableBuilder, from, issueEventModel.getReviewRequester()); } else if (event == IssueEventType.closed || event == IssueEventType.reopened) { if (isMerged) { spannableBuilder.append(" ").append(IssueEventType.merged.name()); @@ -76,7 +82,6 @@ public class TimelineProvider { .append(in) .append(" ") .url(substring(issueEventModel.getCommitId())); - } } else if (event == IssueEventType.assigned || event == IssueEventType.unassigned) { spannableBuilder @@ -99,15 +104,17 @@ public class TimelineProvider { } else if (event == IssueEventType.head_ref_deleted || event == IssueEventType.head_ref_restored) { spannableBuilder.append(" ").append(event.name().replaceAll("_", " "), new BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))); + } else if (event == IssueEventType.milestoned || event == IssueEventType.demilestoned) { + spannableBuilder.append(" ") + .append(event == IssueEventType.milestoned ? "added this to the" : "removed this from the") + .append(" ") + .bold(issueEventModel.getMilestone().getTitle()) + .append(" ") + .append("milestone"); } else { spannableBuilder.append(" ").append(event.name().replaceAll("_", " ")); } - if (event == IssueEventType.milestoned || event == IssueEventType.demilestoned) { - spannableBuilder.append(" ") - .append(event == IssueEventType.milestoned ? to : from) - .append(" ") - .bold(issueEventModel.getMilestone().getTitle()); - } else if (event == IssueEventType.renamed) { + if (event == IssueEventType.renamed) { spannableBuilder .append(" ") .append(from) @@ -123,18 +130,40 @@ public class TimelineProvider { .append("commit") .append(" ") .url(substring(issueEventModel.getCommitId())); + } else if (event == IssueEventType.cross_referenced) { + SourceModel sourceModel = issueEventModel.getSource(); + if (sourceModel != null) { + SpannableBuilder title = SpannableBuilder.builder(); + if (sourceModel.getIssue() != null) { + title.url("#" + sourceModel.getIssue().getNumber()); + } else if (sourceModel.getPullRequest() != null) { + title.url("#" + sourceModel.getPullRequest().getNumber()); + } else if (sourceModel.getCommit() != null) { + title.url(substring(sourceModel.getCommit().getSha())); + } else if (sourceModel.getRepository() != null) { + title.url(sourceModel.getRepository().getName()); + } + if (!InputHelper.isEmpty(title)) { + spannableBuilder.append(" ") + .append(thisString) + .append(" in ") + .append(sourceModel.getType()) + .append(" ") + .append(title); + } + } } - spannableBuilder.append(" ").append(getDate(issueEventModel.getCreatedAt())); + spannableBuilder.append(" ").append(getDate(date)); } } return spannableBuilder; } - private static void appendReviews(@NonNull IssueEvent issueEventModel, @NonNull IssueEventType event, - @NonNull SpannableBuilder spannableBuilder, @NonNull String from, @NonNull User user) { + private static void appendReviews(@NonNull GenericEvent issueEventModel, @NonNull IssueEventType event, + @NonNull SpannableBuilder spannableBuilder, @NonNull String from, + @NonNull User user) { spannableBuilder.append(" "); - User reviewer = issueEventModel.getRequestedReviewer() != null - ? issueEventModel.getRequestedReviewer() : issueEventModel.getIssue() != null ? issueEventModel.getIssue().getUser() : null; + User reviewer = issueEventModel.getRequestedReviewer(); if (reviewer != null && user.getLogin().equalsIgnoreCase(reviewer.getLogin())) { spannableBuilder .append(event == IssueEventType.review_requested @@ -158,11 +187,6 @@ public class TimelineProvider { } } - public static void appendLabels(@NonNull LabelModel labelModel, @NonNull SpannableBuilder spannableBuilder) { - int color = Color.parseColor("#" + labelModel.getColor()); - spannableBuilder.append(" ").append(" " + labelModel.getName() + " ", new LabelSpan(color)); - } - @NonNull private static CharSequence getDate(@Nullable Date date) { return ParseDateFormat.getTimeAgo(date); } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/DrawableHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/DrawableHandler.java index 436f13f5..ad479246 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/DrawableHandler.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/DrawableHandler.java @@ -5,10 +5,10 @@ import android.text.style.ImageSpan; import android.widget.TextView; import com.fastaccess.helper.InputHelper; -import com.fastaccess.helper.Logger; import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter; import net.nightwhistler.htmlspanner.TagNodeHandler; +import net.nightwhistler.htmlspanner.spans.CenterSpan; import org.htmlcleaner.TagNode; @@ -30,15 +30,14 @@ import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; @Override public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end) { String src = node.getAttributeByName("src"); - boolean isGif = "gif".equalsIgnoreCase(node.getAttributeByName("alt")); - Logger.e(isGif); if (!InputHelper.isEmpty(src)) { builder.append(""); if (isNull()) return; + CenterSpan centerSpan = new CenterSpan(); DrawableGetter imageGetter = new DrawableGetter(textView); + builder.setSpan(centerSpan, start, builder.length(), SPAN_EXCLUSIVE_EXCLUSIVE); builder.setSpan(new ImageSpan(imageGetter.getDrawable(src)), start, builder.length(), SPAN_EXCLUSIVE_EXCLUSIVE); appendNewLine(builder); } } - } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/EmojiHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/EmojiHandler.java index 95285615..215ac264 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/EmojiHandler.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/EmojiHandler.java @@ -2,7 +2,7 @@ package com.fastaccess.provider.timeline.handler; import android.text.SpannableStringBuilder; -import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.Logger; import com.fastaccess.provider.emoji.Emoji; import com.fastaccess.provider.emoji.EmojiManager; @@ -18,11 +18,17 @@ public class EmojiHandler extends TagNodeHandler { @Override public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end) { String emoji = node.getAttributeByName("alias"); - if (!InputHelper.isEmpty(emoji)) { + if (emoji != null) { Emoji unicode = EmojiManager.getForAlias(emoji); if (unicode != null && unicode.getUnicode() != null) { builder.replace(start, end, unicode.getUnicode()); } + } else if (node.getText() != null) { + Logger.e(node.getText()); + Emoji unicode = EmojiManager.getForAlias(node.getText().toString()); + if (unicode != null && unicode.getUnicode() != null) { + builder.replace(start, end, unicode.getUnicode()); + } } } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/HrHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/HrHandler.java new file mode 100644 index 00000000..21a75d3b --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/HrHandler.java @@ -0,0 +1,33 @@ +package com.fastaccess.provider.timeline.handler; + +import android.text.SpannableStringBuilder; +import android.text.Spanned; + +import net.nightwhistler.htmlspanner.TagNodeHandler; +import net.nightwhistler.htmlspanner.spans.CenterSpan; + +import org.htmlcleaner.TagNode; + +import lombok.AllArgsConstructor; + +/** + * Created by kosh on 30/07/2017. + */ + +@AllArgsConstructor public class HrHandler extends TagNodeHandler { + + private final int color; + private final int width; + private final boolean isHeader; + + @Override public void handleTagNode(TagNode tagNode, SpannableStringBuilder spannableStringBuilder, int i, int i1) { + spannableStringBuilder.append("\n"); + SpannableStringBuilder builder = new SpannableStringBuilder("$"); + HrSpan hrSpan = new HrSpan(color, width); + builder.setSpan(hrSpan, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new CenterSpan(), 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append("\n"); + spannableStringBuilder.append(builder); + } + +} diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/HrSpan.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/HrSpan.java new file mode 100644 index 00000000..176612d2 --- /dev/null +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/HrSpan.java @@ -0,0 +1,43 @@ +package com.fastaccess.provider.timeline.handler; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.text.style.LineHeightSpan; +import android.text.style.ReplacementSpan; + +public class HrSpan extends ReplacementSpan implements LineHeightSpan { + + private final int width; + private final int color; + + HrSpan(int color, int width) { + this.color = color; + this.width = width; + Drawable drawable = new ColorDrawable(color); + } + + @Override public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + return (int) paint.measureText(text, start, end); + } + + @Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, + int y, int bottom, @NonNull Paint paint) { + final int currentColor = paint.getColor(); + paint.setColor(color); + paint.setStyle(Paint.Style.FILL); + int height = 10; + canvas.drawRect(new Rect(0, bottom - height, (int) x + width, bottom), paint); + paint.setColor(currentColor); + } + + @Override public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) { + fm.top /= 3; + fm.ascent /= 3; + fm.bottom /= 3; + fm.descent /= 3; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/LinkHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/LinkHandler.java index 469f584f..5cd9de55 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/LinkHandler.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/LinkHandler.java @@ -18,6 +18,10 @@ public class LinkHandler extends TagNodeHandler { @Override public void handleTagNode(TagNode node, SpannableStringBuilder spannableStringBuilder, int start, int end) { String href = node.getAttributeByName("href"); - spannableStringBuilder.setSpan(new LinkSpan(href, linkColor), start, end, 33); + if (href != null) { + spannableStringBuilder.setSpan(new LinkSpan(href, linkColor), start, end, 33); + } else if (node.getText() != null) { + spannableStringBuilder.setSpan(new LinkSpan("https://github.com/" + node.getText().toString(), linkColor), start, end, 33); + } } } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/ListsHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/ListsHandler.java index c0ac2c34..28f5641a 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/ListsHandler.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/ListsHandler.java @@ -42,7 +42,7 @@ import lombok.NoArgsConstructor; return node.getParent() == null ? null : node.getParent().getName(); } - @Override public void beforeChildren(TagNode node, SpannableStringBuilder builder) { + @Override public void beforeChildren(TagNode node, SpannableStringBuilder builder) { TodoItems todoItem = null; if (node.getChildTags() != null && node.getChildTags().length > 0) { for (TagNode tagNode : node.getChildTags()) { diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java index 3c4a7ada..ff1bab2d 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java @@ -19,6 +19,7 @@ import android.text.style.AlignmentSpan; import android.text.style.ImageSpan; import net.nightwhistler.htmlspanner.TagNodeHandler; +import net.nightwhistler.htmlspanner.spans.CenterSpan; import org.htmlcleaner.TagNode; @@ -35,12 +36,12 @@ import java.util.List; */ public class TableHandler extends TagNodeHandler { - private int tableWidth = 400; + private int tableWidth = 500; private Typeface typeFace = Typeface.DEFAULT; - private float textSize = 16f; + private float textSize = 30f; private int textColor = Color.BLACK; - private static final int PADDING = 5; + private static final int PADDING = 20; /** * Sets how wide the table should be. @@ -144,7 +145,6 @@ public class TableHandler extends TagNodeHandler { int rowHeight = 0; for (Spanned cell : row) { - StaticLayout layout = new StaticLayout(cell, textPaint, columnWidth - 2 * PADDING, Alignment.ALIGN_NORMAL, 1f, 0f, true); @@ -165,19 +165,14 @@ public class TableHandler extends TagNodeHandler { drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); builder.setSpan(new ImageSpan(drawable), start + i, builder.length(), 33); - } - - /* - We add an empty last row to work around a rendering issue where - the last row would appear detached. - */ builder.append("\uFFFC"); - Drawable drawable = new TableRowDrawable(new ArrayList(), table.isDrawBorder()); + Drawable drawable = new TableRowDrawable(new ArrayList<>(), table.isDrawBorder()); drawable.setBounds(0, 0, tableWidth, 1); builder.setSpan(new ImageSpan(drawable), builder.length() - 1, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); builder.setSpan((AlignmentSpan) () -> Alignment.ALIGN_CENTER, start, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new CenterSpan(), start, builder.length(), 33); builder.append("\n"); } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/DrawableGetter.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/DrawableGetter.java index e461c72a..759fe787 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/DrawableGetter.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/DrawableGetter.java @@ -3,14 +3,12 @@ package com.fastaccess.provider.timeline.handler.drawable; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; import android.text.Html; import android.widget.TextView; import com.bumptech.glide.GenericRequestBuilder; import com.bumptech.glide.Glide; import com.fastaccess.R; -import com.fastaccess.helper.Logger; import java.lang.ref.WeakReference; import java.util.HashSet; @@ -22,7 +20,7 @@ import java.util.Set; public class DrawableGetter implements Html.ImageGetter, Drawable.Callback { private WeakReference container; - private final Set cachedTargets; + private final Set cachedTargets; public DrawableGetter(TextView tv) { tv.setTag(R.id.drawable_callback, this); @@ -30,27 +28,14 @@ public class DrawableGetter implements Html.ImageGetter, Drawable.Callback { this.cachedTargets = new HashSet<>(); } - public void clear(@NonNull DrawableGetter drawableGetter) { - if (drawableGetter.cachedTargets != null) { - for (GifBitmapTarget target : drawableGetter.cachedTargets) { - Logger.e("is clearing"); - Glide.clear(target); - } - } - } - @Override public Drawable getDrawable(@NonNull String url) { final UrlDrawable urlDrawable = new UrlDrawable(); if (container != null && container.get() != null) { Context context = container.get().getContext(); - Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_image); - urlDrawable.setDrawable(drawable); - container.get().setText(container.get().getText()); - container.get().invalidate(); final GenericRequestBuilder load = Glide.with(context) .load(url) .dontAnimate(); - final GifBitmapTarget target = new GifBitmapTarget(urlDrawable, container); + final GlideDrawableTarget target = new GlideDrawableTarget(urlDrawable, container); load.into(target); cachedTargets.add(target); } @@ -66,4 +51,12 @@ public class DrawableGetter implements Html.ImageGetter, Drawable.Callback { @Override public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {} @Override public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {} + + public void clear(@NonNull DrawableGetter drawableGetter) { + if (drawableGetter.cachedTargets != null) { + for (GlideDrawableTarget target : drawableGetter.cachedTargets) { + Glide.clear(target); + } + } + } } diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/GifBitmapTarget.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/GlideDrawableTarget.java similarity index 88% rename from app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/GifBitmapTarget.java rename to app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/GlideDrawableTarget.java index 62df871c..428bab2d 100644 --- a/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/GifBitmapTarget.java +++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/drawable/GlideDrawableTarget.java @@ -11,11 +11,11 @@ import com.fastaccess.R; import java.lang.ref.WeakReference; -class GifBitmapTarget extends SimpleTarget { +class GlideDrawableTarget extends SimpleTarget { private final UrlDrawable urlDrawable; private final WeakReference container; - GifBitmapTarget(UrlDrawable urlDrawable, WeakReference container) { + GlideDrawableTarget(UrlDrawable urlDrawable, WeakReference container) { this.urlDrawable = urlDrawable; this.container = container; } @@ -34,7 +34,7 @@ class GifBitmapTarget extends SimpleTarget { width = (float) resource.getIntrinsicWidth() * multiplier; height = (float) resource.getIntrinsicHeight() * multiplier; } - Rect rect = new Rect(0, 0, Math.round(width), Math.round(height)); + Rect rect = new Rect(0, 0, (int) Math.round(width / 1.3), (int) Math.round(height / 1.3)); resource.setBounds(rect); urlDrawable.setBounds(rect); urlDrawable.setDrawable(resource); diff --git a/app/src/main/java/com/fastaccess/ui/adapter/CommitCommentsAdapter.kt b/app/src/main/java/com/fastaccess/ui/adapter/CommitCommentsAdapter.kt new file mode 100644 index 00000000..1b470b0f --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/CommitCommentsAdapter.kt @@ -0,0 +1,26 @@ +package com.fastaccess.ui.adapter + +import android.view.ViewGroup +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.ui.adapter.callback.OnToggleView +import com.fastaccess.ui.adapter.viewholder.CommitCommentsViewHolder +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by kosh on 15/08/2017. + */ +class CommitCommentsAdapter(data: List, + listener: BaseViewHolder.OnItemClickListener, + var onToggleView: OnToggleView) + : BaseRecyclerAdapter>(data, listener) { + + override fun viewHolder(parent: ViewGroup, viewType: Int): CommitCommentsViewHolder { + return CommitCommentsViewHolder.newInstance(parent, this, onToggleView) + } + + override fun onBindView(holder: CommitCommentsViewHolder, position: Int) { + holder.bind(data[position]) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/EmojiAdapter.kt b/app/src/main/java/com/fastaccess/ui/adapter/EmojiAdapter.kt new file mode 100644 index 00000000..d1041c51 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/EmojiAdapter.kt @@ -0,0 +1,55 @@ +package com.fastaccess.ui.adapter + +import android.view.ViewGroup +import android.widget.Filter +import android.widget.Filterable +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.ui.adapter.viewholder.EmojiViewHolder +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by kosh on 17/08/2017. + */ +class EmojiAdapter(listener: BaseViewHolder.OnItemClickListener) + : BaseRecyclerAdapter>(listener), Filterable { + + var copiedList = mutableListOf() + + override fun viewHolder(parent: ViewGroup, viewType: Int): EmojiViewHolder { + return EmojiViewHolder.newInstance(parent, this) + } + + override fun onBindView(holder: EmojiViewHolder, position: Int) { + holder.bind(data[position]) + } + + override fun getFilter(): Filter { + return object : Filter() { + override fun performFiltering(constraint: CharSequence): Filter.FilterResults { + if (copiedList.isEmpty()) { + copiedList.addAll(data) + } + val text = constraint.toString().toLowerCase() + val filteredResults: List = if (text.isNotBlank()) { + val data = data.filter { + text in it.tags || it.description.contains(text) || + it.unicode.contains(text) || text in it.aliases + } + if (data.isNotEmpty()) data + else copiedList + } else { + copiedList + } + val results = FilterResults() + results.values = filteredResults + results.count = filteredResults.size + return results + } + + override fun publishResults(var1: CharSequence, results: Filter.FilterResults) { + insertItems(results.values as List) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/GistFilesAdapter.java b/app/src/main/java/com/fastaccess/ui/adapter/GistFilesAdapter.java index c6871899..e7899d7d 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/GistFilesAdapter.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/GistFilesAdapter.java @@ -17,13 +17,20 @@ import java.util.List; public class GistFilesAdapter extends BaseRecyclerAdapter> { + private boolean isOwner; - public GistFilesAdapter(@NonNull List data, @Nullable BaseViewHolder.OnItemClickListener listener) { + public GistFilesAdapter(@NonNull List data, + @Nullable BaseViewHolder.OnItemClickListener listener, boolean isOwner) { super(data, listener); + this.isOwner = isOwner; + } + + public void setOwner(boolean owner) { + isOwner = owner; } @Override protected GistFilesViewHolder viewHolder(ViewGroup parent, int viewType) { - return GistFilesViewHolder.newInstance(parent, this); + return GistFilesViewHolder.newInstance(parent, this, isOwner); } @Override protected void onBindView(GistFilesViewHolder holder, int position) { diff --git a/app/src/main/java/com/fastaccess/ui/adapter/IssuePullsTimelineAdapter.java b/app/src/main/java/com/fastaccess/ui/adapter/IssuesTimelineAdapter.java similarity index 67% rename from app/src/main/java/com/fastaccess/ui/adapter/IssuePullsTimelineAdapter.java rename to app/src/main/java/com/fastaccess/ui/adapter/IssuesTimelineAdapter.java index f6ec0f3f..3cea90b7 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/IssuePullsTimelineAdapter.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/IssuesTimelineAdapter.java @@ -4,15 +4,18 @@ import android.support.annotation.NonNull; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.ViewGroup; +import com.fastaccess.R; import com.fastaccess.data.dao.TimelineModel; import com.fastaccess.ui.adapter.callback.OnToggleView; import com.fastaccess.ui.adapter.callback.ReactionsCallback; +import com.fastaccess.ui.adapter.viewholder.CommitThreadViewHolder; import com.fastaccess.ui.adapter.viewholder.GroupedReviewsViewHolder; import com.fastaccess.ui.adapter.viewholder.IssueDetailsViewHolder; import com.fastaccess.ui.adapter.viewholder.IssueTimelineViewHolder; import com.fastaccess.ui.adapter.viewholder.PullStatusViewHolder; import com.fastaccess.ui.adapter.viewholder.ReviewsViewHolder; import com.fastaccess.ui.adapter.viewholder.TimelineCommentsViewHolder; +import com.fastaccess.ui.adapter.viewholder.UnknownTypeViewHolder; import com.fastaccess.ui.modules.repos.pull_requests.pull_request.details.timeline.timeline.PullRequestTimelineMvp.ReviewCommentCallback; import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter; import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; @@ -23,7 +26,7 @@ import java.util.List; * Created by Kosh on 13 Dec 2016, 1:44 AM */ -public class IssuePullsTimelineAdapter extends BaseRecyclerAdapter> { private final OnToggleView onToggleView; @@ -34,9 +37,9 @@ public class IssuePullsTimelineAdapter extends BaseRecyclerAdapter data, OnToggleView onToggleView, boolean showEmojies, - ReactionsCallback reactionsCallback, boolean isMerged, - ReviewCommentCallback reviewCommentCallback, String repoOwner, String poster) { + public IssuesTimelineAdapter(@NonNull List data, OnToggleView onToggleView, boolean showEmojies, + ReactionsCallback reactionsCallback, boolean isMerged, + ReviewCommentCallback reviewCommentCallback, String repoOwner, String poster) { super(data); this.onToggleView = onToggleView; this.showEmojies = showEmojies; @@ -47,23 +50,27 @@ public class IssuePullsTimelineAdapter extends BaseRecyclerAdapter data, OnToggleView onToggleView, boolean showEmojies, - ReactionsCallback reactionsCallback, String repoOwner, String poster) { + public IssuesTimelineAdapter(@NonNull List data, OnToggleView onToggleView, boolean showEmojies, + ReactionsCallback reactionsCallback, String repoOwner, String poster) { this(data, onToggleView, showEmojies, reactionsCallback, false, null, repoOwner, poster); } @Override protected BaseViewHolder viewHolder(ViewGroup parent, int viewType) { - if (viewType == TimelineModel.HEADER) { + if (viewType == 0) { + return new UnknownTypeViewHolder(BaseViewHolder.getView(parent, R.layout.unknown_row_item)); + } else if (viewType == TimelineModel.HEADER) { return IssueDetailsViewHolder.newInstance(parent, this, onToggleView, reactionsCallback, repoOwner, poster); } else if (viewType == TimelineModel.EVENT) { return IssueTimelineViewHolder.newInstance(parent, this, isMerged); - } else if (viewType == TimelineModel.STATUS) { - return PullStatusViewHolder.newInstance(parent); } else if (viewType == TimelineModel.REVIEW) { - return ReviewsViewHolder.newInstance(parent, this); - } else if (viewType == TimelineModel.GROUPED_REVIEW) { + return ReviewsViewHolder.Companion.newInstance(parent, this); + } else if (viewType == TimelineModel.GROUP) { return GroupedReviewsViewHolder.newInstance(parent, this, onToggleView, reactionsCallback, reviewCommentCallback, repoOwner, poster); + } else if (viewType == TimelineModel.COMMIT_COMMENTS) { + return CommitThreadViewHolder.Companion.newInstance(parent, this, onToggleView); + } else if (viewType == TimelineModel.STATUS) { + return PullStatusViewHolder.newInstance(parent); } return TimelineCommentsViewHolder.newInstance(parent, this, onToggleView, showEmojies, reactionsCallback, repoOwner, poster); @@ -77,12 +84,14 @@ public class IssuePullsTimelineAdapter extends BaseRecyclerAdapter> { public interface OnSelectLabel { - boolean isLabelSelected(int position); + boolean isLabelSelected(LabelModel labelModel); - void onToggleSelection(int position, boolean select); + void onToggleSelection(LabelModel labelModel, boolean select); } @Nullable private OnSelectLabel onSelectLabel; diff --git a/app/src/main/java/com/fastaccess/ui/adapter/LoginAdapter.kt b/app/src/main/java/com/fastaccess/ui/adapter/LoginAdapter.kt index da012001..df05ca4c 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/LoginAdapter.kt +++ b/app/src/main/java/com/fastaccess/ui/adapter/LoginAdapter.kt @@ -9,7 +9,8 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder /** * Created by Kosh on 09 Jul 2017, 5:00 PM */ -class LoginAdapter constructor(val small: Boolean = false) : BaseRecyclerAdapter>() { +class LoginAdapter constructor(private val small: Boolean = false) + : BaseRecyclerAdapter>() { override fun onBindView(holder: LoginViewHolder, position: Int) { holder.bind(getItem(position)) diff --git a/app/src/main/java/com/fastaccess/ui/adapter/ProfilePinnedReposAdapter.kt b/app/src/main/java/com/fastaccess/ui/adapter/ProfilePinnedReposAdapter.kt new file mode 100644 index 00000000..eb14b699 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/ProfilePinnedReposAdapter.kt @@ -0,0 +1,27 @@ +package com.fastaccess.ui.adapter + +import android.view.ViewGroup +import com.fastaccess.ui.adapter.viewholder.ProfilePinnedReposViewHolder +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder +import pr.GetPinnedReposQuery +import java.text.NumberFormat + +/** + * Created by kosh on 09/08/2017. + */ + +class ProfilePinnedReposAdapter(data: List) : BaseRecyclerAdapter>(data) { + + private val numberFormat = NumberFormat.getNumberInstance()!! + + override fun viewHolder(parent: ViewGroup, viewType: Int): ProfilePinnedReposViewHolder { + return ProfilePinnedReposViewHolder.newInstance(parent, this) + } + + override fun onBindView(holder: ProfilePinnedReposViewHolder, position: Int) { + holder.bind(data[position], numberFormat) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/ReviewCommentsAdapter.java b/app/src/main/java/com/fastaccess/ui/adapter/ReviewCommentsAdapter.java index 45d3133f..9b42ca6b 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/ReviewCommentsAdapter.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/ReviewCommentsAdapter.java @@ -44,4 +44,4 @@ public class ReviewCommentsAdapter extends BaseRecyclerAdapter { - FontTextView topic = (FontTextView) view; Intent intent = new Intent(new Intent(App.getInstance().getApplicationContext(), SearchActivity.class)); - intent.putExtra("search", topic.getText().toString()); + intent.putExtra("search", "topic:\"" + item + "\""); view.getContext().startActivity(intent); }); holder.bind(getItem(position)); diff --git a/app/src/main/java/com/fastaccess/ui/adapter/TrendingAdapter.kt b/app/src/main/java/com/fastaccess/ui/adapter/TrendingAdapter.kt index fe60ffb8..252ab5c9 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/TrendingAdapter.kt +++ b/app/src/main/java/com/fastaccess/ui/adapter/TrendingAdapter.kt @@ -13,6 +13,7 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder class TrendingAdapter(data: MutableList) : BaseRecyclerAdapter>(data) { + override fun viewHolder(parent: ViewGroup?, viewType: Int): TrendingViewHolder { return TrendingViewHolder(BaseViewHolder.getView(parent!!, R.layout.trending_row_item), this) } diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommentsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommentsViewHolder.java index ec13039b..fcc84c86 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommentsViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommentsViewHolder.java @@ -31,6 +31,7 @@ public class CommentsViewHolder extends BaseViewHolder { @BindView(R.id.comment) FontTextView comment; @BindView(R.id.toggleHolder) View toggleHolder; @BindView(R.id.toggle) AppCompatImageView toggle; + private final ViewGroup viewGroup; @Override public void onClick(View v) { if (v.getId() == R.id.toggleHolder) { @@ -40,16 +41,18 @@ public class CommentsViewHolder extends BaseViewHolder { } } - private CommentsViewHolder(@NonNull View itemView, @Nullable BaseRecyclerAdapter adapter) { + private CommentsViewHolder(@NonNull View itemView, @Nullable BaseRecyclerAdapter adapter, @NonNull ViewGroup viewGroup) { super(itemView, adapter); itemView.setOnClickListener(null); itemView.setOnLongClickListener(null); toggleHolder.setOnClickListener(this); toggle.setOnClickListener(this); + toggle.setOnLongClickListener(this); + this.viewGroup = viewGroup; } public static CommentsViewHolder newInstance(@NonNull ViewGroup viewGroup, @Nullable BaseRecyclerAdapter adapter) { - return new CommentsViewHolder(getView(viewGroup, R.layout.no_emojies_comments_row_item), adapter); + return new CommentsViewHolder(getView(viewGroup, R.layout.no_emojies_comments_row_item), adapter, viewGroup); } @Override public void bind(@NonNull Comment commentsModel) { @@ -60,7 +63,7 @@ public class CommentsViewHolder extends BaseViewHolder { avatar.setUrl(null, null, false, false); } if (!InputHelper.isEmpty(commentsModel.getBodyHtml())) { - HtmlHelper.htmlIntoTextView(comment, commentsModel.getBodyHtml()); + HtmlHelper.htmlIntoTextView(comment, commentsModel.getBodyHtml(), viewGroup.getWidth()); } else { comment.setText(""); } diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommitCommentsViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommitCommentsViewHolder.kt new file mode 100644 index 00000000..9cf75c62 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommitCommentsViewHolder.kt @@ -0,0 +1,97 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.support.transition.ChangeBounds +import android.support.transition.TransitionManager +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.helper.InputHelper +import com.fastaccess.helper.ParseDateFormat +import com.fastaccess.provider.markdown.MarkDownProvider +import com.fastaccess.provider.scheme.LinkParserHelper +import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter +import com.fastaccess.ui.adapter.callback.OnToggleView +import com.fastaccess.ui.widgets.AvatarLayout +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.ForegroundImageView +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by kosh on 15/08/2017. + */ +class CommitCommentsViewHolder private constructor(view: View, adapter: BaseRecyclerAdapter<*, *, *>, + val viewGroup: ViewGroup, val onToggleView: OnToggleView) + : BaseViewHolder(view, adapter) { + + init { + itemView.setOnClickListener(null) + itemView.setOnLongClickListener(null) + commentMenu.setOnClickListener(this) + commentMenu.setOnLongClickListener(this) + toggle.visibility = View.GONE + commentMenu.visibility = View.GONE + commentOptions.visibility = View.GONE + } + + @BindView(R.id.avatarView) lateinit var avatar: AvatarLayout + @BindView(R.id.name) lateinit var name: FontTextView + @BindView(R.id.date) lateinit var date: FontTextView + @BindView(R.id.toggle) lateinit var toggle: ForegroundImageView + @BindView(R.id.commentMenu) lateinit var commentMenu: ForegroundImageView + @BindView(R.id.comment) lateinit var comment: FontTextView + @BindView(R.id.commentOptions) lateinit var commentOptions: View + + override fun onClick(v: View) { + if (v.id == R.id.toggle || v.id == R.id.toggleHolder) { + val position = adapterPosition + onToggleView.onToggle(position.toLong(), !onToggleView.isCollapsed(position.toLong())) + onToggle(onToggleView.isCollapsed(position.toLong()), true) + } else { + super.onClick(v) + } + } + + override fun bind(t: Comment) { + val author3 = t.user + if (author3 != null) { + avatar.setUrl(author3.avatarUrl, author3.login, false, LinkParserHelper.isEnterprise(author3.url)) + name.text = author3.login + } else { + avatar.setUrl(null, null, false, false) + name.text = null + } + if (!InputHelper.isEmpty(t.body)) { + MarkDownProvider.setMdText(comment, t.body) + } else { + comment.text = "" + } + if (t.createdAt == t.updatedAt) { + date.text = String.format("%s %s", ParseDateFormat.getTimeAgo(t.updatedAt), itemView + .resources.getString(R.string.edited)) + } else { + date.text = ParseDateFormat.getTimeAgo(t.createdAt) + } + onToggle(onToggleView.isCollapsed(adapterPosition.toLong()), false) + } + + private fun onToggle(expanded: Boolean, animate: Boolean) { + if (animate) { + TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) + } + toggle.rotation = if (!expanded) 0.0f else 180f + } + + override fun onViewIsDetaching() { + val drawableGetter = comment.getTag(R.id.drawable_callback) as DrawableGetter? + drawableGetter?.clear(drawableGetter) + } + + companion object { + fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>, onToggleView: OnToggleView): CommitCommentsViewHolder { + return CommitCommentsViewHolder(getView(parent, R.layout.comments_row_item), adapter, parent, onToggleView) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommitThreadViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommitThreadViewHolder.kt new file mode 100644 index 00000000..8fcbdac0 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/CommitThreadViewHolder.kt @@ -0,0 +1,83 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.annotation.SuppressLint +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.data.dao.TimelineModel +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.ui.adapter.CommitCommentsAdapter +import com.fastaccess.ui.adapter.callback.OnToggleView +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.SpannableBuilder +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder +import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView + +/** + * Created by kosh on 15/08/2017. + */ +class CommitThreadViewHolder private constructor(view: View, + adapter: BaseRecyclerAdapter<*, *, *>, + val onToggleView: OnToggleView) + : BaseViewHolder(view, adapter), BaseViewHolder.OnItemClickListener { + + @BindView(R.id.pathText) lateinit var pathText: FontTextView + @BindView(R.id.toggle) lateinit var toggle: View + @BindView(R.id.toggleHolder) lateinit var toggleHolder: View + @BindView(R.id.commitComments) lateinit var commitComments: DynamicRecyclerView + + init { + toggleHolder.setOnClickListener(this) + toggle.setOnClickListener(this) + itemView.setOnClickListener(null) + itemView.setOnLongClickListener(null) + } + + override fun onClick(v: View) { + if (v.id == R.id.toggle || v.id == R.id.toggleHolder) { + val position = adapterPosition + onToggleView.onToggle(position.toLong(), !onToggleView.isCollapsed(position.toLong())) + onToggle(onToggleView.isCollapsed(position.toLong())) + } + } + + @SuppressLint("SetTextI18n") + override fun bind(model: TimelineModel) { + val t = model.commit + t?.let { + val builder = SpannableBuilder.builder() + pathText.text = builder.append("${if (!it.login.isNullOrBlank()) it.login else ""} commented on") + .append(if (!it.path.isNullOrEmpty()) { + " ${it.path}#L${it.position} in " + } else { + " " + }) + .url(it.commitId.substring(0, 7)) + it.comments?.let { + if (!it.isEmpty()) commitComments.adapter = CommitCommentsAdapter(it, this, onToggleView) + } + } + onToggle(onToggleView.isCollapsed(adapterPosition.toLong())) + } + + + private fun onToggle(expanded: Boolean) { + toggle.rotation = if (!expanded) 0.0f else 180f + commitComments.visibility = if (!expanded) View.GONE + else if (commitComments.adapter != null) View.VISIBLE + else View.GONE + } + + override fun onItemClick(position: Int, v: View?, item: Comment) {} + + override fun onItemLongClick(position: Int, v: View?, item: Comment) {} + + companion object { + fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>, + onToggleView: OnToggleView): CommitThreadViewHolder { + return CommitThreadViewHolder(getView(parent, R.layout.grouped_commit_comment_row), adapter, onToggleView) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/EmojiViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/EmojiViewHolder.kt new file mode 100644 index 00000000..c26bb6e2 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/EmojiViewHolder.kt @@ -0,0 +1,29 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by kosh on 17/08/2017. + */ +class EmojiViewHolder private constructor(view: View, adapter: BaseRecyclerAdapter<*, *, *>) + : BaseViewHolder(view, adapter) { + + @BindView(R.id.emoji) lateinit var emojiTextView: FontTextView + + override fun bind(t: Emoji) { + emojiTextView.text = t.unicode + } + + companion object { + fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>): EmojiViewHolder { + return EmojiViewHolder(getView(parent, R.layout.emoji_row_item), adapter) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GistFilesViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GistFilesViewHolder.java index a81dfc58..34494296 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GistFilesViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GistFilesViewHolder.java @@ -9,6 +9,7 @@ import com.fastaccess.R; import com.fastaccess.data.dao.FilesListModel; import com.fastaccess.ui.adapter.GistFilesAdapter; import com.fastaccess.ui.widgets.FontTextView; +import com.fastaccess.ui.widgets.ForegroundImageView; import com.fastaccess.ui.widgets.SpannableBuilder; import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; @@ -20,23 +21,32 @@ import butterknife.BindView; public class GistFilesViewHolder extends BaseViewHolder { - @BindView(R.id.fileName) FontTextView fileName; @BindView(R.id.language) FontTextView language; @BindView(R.id.size) FontTextView size; + @BindView(R.id.delete) ForegroundImageView delete; + @BindView(R.id.edit) ForegroundImageView edit; + private boolean isOwner; - private GistFilesViewHolder(@NonNull View itemView, GistFilesAdapter adapter) { + private GistFilesViewHolder(@NonNull View itemView, GistFilesAdapter adapter, boolean isOwner) { super(itemView, adapter); - + this.isOwner = isOwner; + if (isOwner) { + delete.setOnClickListener(this); + edit.setOnClickListener(this); + } } - public static GistFilesViewHolder newInstance(@NonNull ViewGroup parent, GistFilesAdapter adapter) { - return new GistFilesViewHolder(getView(parent, R.layout.gist_files_row_item), adapter); + public static GistFilesViewHolder newInstance(@NonNull ViewGroup parent, GistFilesAdapter adapter, boolean isOwner) { + return new GistFilesViewHolder(getView(parent, R.layout.gist_files_row_item), adapter, isOwner); } @Override public void bind(@NonNull FilesListModel filesListModel) { fileName.setText(filesListModel.getFilename()); language.setText(SpannableBuilder.builder().bold(filesListModel.getType())); size.setText(Formatter.formatFileSize(size.getContext(), filesListModel.getSize())); + delete.setVisibility(isOwner ? View.VISIBLE : View.GONE); + edit.setVisibility(isOwner ? View.VISIBLE : View.GONE); } + } diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GroupedReviewsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GroupedReviewsViewHolder.java index 9b334dd9..cc4f3b26 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GroupedReviewsViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/GroupedReviewsViewHolder.java @@ -38,6 +38,7 @@ public class GroupedReviewsViewHolder extends BaseViewHolder impl @BindView(R.id.minimized) View minimized; @BindView(R.id.addCommentPreview) View addCommentPreview; @BindView(R.id.toggleHolder) LinearLayout toggleHolder; + @BindView(R.id.bottomToggle) View bottomToggle; private final int patchAdditionColor; private final int patchDeletionColor; @@ -51,7 +52,7 @@ public class GroupedReviewsViewHolder extends BaseViewHolder impl private String poster; @Override public void onClick(View v) { - if (v.getId() == R.id.toggle || v.getId() == R.id.toggleHolder) { + if (v.getId() == R.id.toggle || v.getId() == R.id.toggleHolder || v.getId() == R.id.bottomToggle) { long position = getId(); onToggleView.onToggle(position, !onToggleView.isCollapsed(position)); onToggle(onToggleView.isCollapsed(position), true); @@ -76,6 +77,7 @@ public class GroupedReviewsViewHolder extends BaseViewHolder impl this.onToggleView = onToggleView; this.repoOwner = repoOwner; this.poster = poster; + bottomToggle.setOnClickListener(this); nestedRecyclerView.setNestedScrollingEnabled(false); addCommentPreview.setOnClickListener(this); toggle.setOnClickListener(this); @@ -94,7 +96,7 @@ public class GroupedReviewsViewHolder extends BaseViewHolder impl } @Override public void bind(@NonNull TimelineModel model) { - GroupedReviewModel groupedReviewModel = model.getGroupedReview(); + GroupedReviewModel groupedReviewModel = model.getGroupedReviewModel(); this.pathText = groupedReviewModel.getDiffText(); name.setText(groupedReviewModel.getPath()); stateImage.setImageResource(R.drawable.ic_eye); @@ -144,4 +146,4 @@ public class GroupedReviewsViewHolder extends BaseViewHolder impl private void setPatchText(@NonNull String text) { patch.setText(DiffLineSpan.getSpannable(text, patchAdditionColor, patchDeletionColor, patchRefColor, true)); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueDetailsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueDetailsViewHolder.java index 3d14dc32..628e854e 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueDetailsViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueDetailsViewHolder.java @@ -16,7 +16,6 @@ import com.fastaccess.data.dao.model.Issue; import com.fastaccess.data.dao.model.PullRequest; import com.fastaccess.data.dao.model.User; import com.fastaccess.helper.InputHelper; -import com.fastaccess.helper.Logger; import com.fastaccess.helper.ParseDateFormat; import com.fastaccess.provider.scheme.LinkParserHelper; import com.fastaccess.provider.timeline.CommentsHelper; @@ -194,8 +193,8 @@ public class IssueDetailsViewHolder extends BaseViewHolder { if (reactionsModel != null) { appendEmojies(reactionsModel); } - if (!InputHelper.isEmpty(description)) { - HtmlHelper.htmlIntoTextView(comment, description); + if (description != null && !description.trim().isEmpty()) { + HtmlHelper.htmlIntoTextView(comment, description, viewGroup.getWidth()); } else { comment.setText(R.string.no_description_provided); } diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueTimelineViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueTimelineViewHolder.java index 93da8528..bb7ca244 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueTimelineViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/IssueTimelineViewHolder.java @@ -1,27 +1,20 @@ package com.fastaccess.ui.adapter.viewholder; -import android.graphics.Color; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; import android.view.ViewGroup; import com.fastaccess.R; -import com.fastaccess.data.dao.LabelModel; import com.fastaccess.data.dao.TimelineModel; -import com.fastaccess.data.dao.model.IssueEvent; +import com.fastaccess.data.dao.timeline.GenericEvent; import com.fastaccess.data.dao.types.IssueEventType; -import com.fastaccess.helper.InputHelper; -import com.fastaccess.helper.Logger; -import com.fastaccess.helper.ParseDateFormat; import com.fastaccess.provider.scheme.LinkParserHelper; import com.fastaccess.provider.timeline.TimelineProvider; import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter; import com.fastaccess.ui.widgets.AvatarLayout; import com.fastaccess.ui.widgets.FontTextView; import com.fastaccess.ui.widgets.ForegroundImageView; -import com.fastaccess.ui.widgets.LabelSpan; -import com.fastaccess.ui.widgets.SpannableBuilder; import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter; import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; @@ -48,7 +41,7 @@ public class IssueTimelineViewHolder extends BaseViewHolder { } @Override public void bind(@NonNull TimelineModel timelineModel) { - IssueEvent issueEventModel = timelineModel.getEvent(); + GenericEvent issueEventModel = timelineModel.getGenericEvent(); IssueEventType event = issueEventModel.getEvent(); if (issueEventModel.getAssignee() != null && issueEventModel.getAssigner() != null) { avatarLayout.setUrl(issueEventModel.getAssigner().getAvatarUrl(), issueEventModel.getAssigner().getLogin(), @@ -57,37 +50,21 @@ public class IssueTimelineViewHolder extends BaseViewHolder { if (issueEventModel.getActor() != null) { avatarLayout.setUrl(issueEventModel.getActor().getAvatarUrl(), issueEventModel.getActor().getLogin(), false, LinkParserHelper.isEnterprise(issueEventModel.getUrl())); + } else if (issueEventModel.getAuthor() != null) { + avatarLayout.setUrl(issueEventModel.getAuthor().getAvatarUrl(), issueEventModel.getAuthor().getLogin(), + false, LinkParserHelper.isEnterprise(issueEventModel.getUrl())); } } if (event != null) { stateImage.setContentDescription(event.name()); stateImage.setImageResource(event.getIconResId()); } - if (issueEventModel.getLabels() == null || issueEventModel.getLabels().isEmpty()) { - if (event != null) { - stateText.setText(TimelineProvider.getStyledEvents(issueEventModel, itemView.getContext(), isMerged)); - } else { - stateText.setText(""); - stateImage.setImageResource(R.drawable.ic_label); - } + if (event != null) { + stateText.setText(TimelineProvider.getStyledEvents(issueEventModel, itemView.getContext(), isMerged)); } else { - if (event != null) { - SpannableBuilder spannableBuilder = SpannableBuilder.builder(); - if (issueEventModel.getAssignee() != null && issueEventModel.getAssigner() != null) { - spannableBuilder.bold(issueEventModel.getAssigner().getLogin(), new LabelSpan(Color.TRANSPARENT)); - } else if (issueEventModel.getActor() != null) { - spannableBuilder.bold(issueEventModel.getActor().getLogin(), new LabelSpan(Color.TRANSPARENT)); - } - spannableBuilder.append(" ").append(event.name().replaceAll("_", " "), new LabelSpan(Color.TRANSPARENT)); - for (LabelModel labelModel : issueEventModel.getLabels()) { - TimelineProvider.appendLabels(labelModel, spannableBuilder); - } - spannableBuilder.append(" ").append(ParseDateFormat.getTimeAgo(issueEventModel.getCreatedAt()), new LabelSpan(Color.TRANSPARENT)); - stateText.setText(spannableBuilder); - stateImage.setImageResource(R.drawable.ic_label); - } + stateText.setText(""); + stateImage.setImageResource(R.drawable.ic_label); } - itemView.setEnabled(!InputHelper.isEmpty(issueEventModel.getCommitUrl())); } @Override protected void onViewIsDetaching() { diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LabelsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LabelsViewHolder.java index a98aca38..6f17803b 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LabelsViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LabelsViewHolder.java @@ -31,7 +31,10 @@ public class LabelsViewHolder extends BaseViewHolder { @Override public void onClick(View v) { if (onSelectLabel != null) { int position = getAdapterPosition(); - onSelectLabel.onToggleSelection(position, !onSelectLabel.isLabelSelected(position)); + if (adapter != null) { + LabelModel labelModel = (LabelModel) adapter.getItem(position); + onSelectLabel.onToggleSelection(labelModel, !onSelectLabel.isLabelSelected(labelModel)); + } } else { super.onClick(v); } @@ -53,12 +56,12 @@ public class LabelsViewHolder extends BaseViewHolder { int color = Color.parseColor(labelModel.getColor().startsWith("#") ? labelModel.getColor() : "#" + labelModel.getColor()); colorImage.setBackgroundColor(color); if (onSelectLabel != null) { - if (onSelectLabel.isLabelSelected(getAdapterPosition())) { + if (onSelectLabel.isLabelSelected(labelModel)) { name.setTextColor(ViewHelper.generateTextColor(color)); } else { name.setTextColor(ViewHelper.getPrimaryTextColor(itemView.getContext())); } - itemView.setBackgroundColor(onSelectLabel.isLabelSelected(getAdapterPosition()) ? color : 0); + itemView.setBackgroundColor(onSelectLabel.isLabelSelected(labelModel) ? color : 0); } } else { colorImage.setBackgroundColor(0); diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LoginViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LoginViewHolder.kt index d5600260..77945c82 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LoginViewHolder.kt +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/LoginViewHolder.kt @@ -4,12 +4,11 @@ import android.annotation.SuppressLint import android.net.Uri import android.view.View import android.view.ViewGroup +import butterknife.BindView import com.fastaccess.R import com.fastaccess.data.dao.model.Login import com.fastaccess.ui.widgets.AvatarLayout import com.fastaccess.ui.widgets.FontTextView -import com.fastaccess.ui.widgets.bindOptionalView -import com.fastaccess.ui.widgets.bindView import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder @@ -19,8 +18,9 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder class LoginViewHolder private constructor(itemView: View, adapter: BaseRecyclerAdapter<*, *, *>?) : BaseViewHolder(itemView, adapter) { - val avatarLayout: AvatarLayout? by bindOptionalView(R.id.avatarLayout) - val title: FontTextView by bindView(R.id.title) + + val avatarLayout: AvatarLayout? by lazy { itemView.findViewById(R.id.avatarLayout) } + @BindView(R.id.title) lateinit var title: FontTextView @SuppressLint("SetTextI18n") override fun bind(login: Login) { diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ProfilePinnedReposViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ProfilePinnedReposViewHolder.kt new file mode 100644 index 00000000..f26e124e --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ProfilePinnedReposViewHolder.kt @@ -0,0 +1,53 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.graphics.Color +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder +import pr.GetPinnedReposQuery +import java.text.NumberFormat + +/** + * Created by kosh on 09/08/2017. + */ +class ProfilePinnedReposViewHolder private constructor(view: View, adapter: BaseRecyclerAdapter<*, *, *>) : + BaseViewHolder(view, adapter) { + + @BindView(R.id.title) lateinit var title: FontTextView + @BindView(R.id.issues) lateinit var issues: FontTextView + @BindView(R.id.pullRequests) lateinit var pullRequest: FontTextView + @BindView(R.id.language) lateinit var language: FontTextView + @BindView(R.id.stars) lateinit var stars: FontTextView + @BindView(R.id.forks) lateinit var forks: FontTextView + + override fun bind(t: GetPinnedReposQuery.Node) {} + + fun bind(t: GetPinnedReposQuery.Node, numberFormat: NumberFormat) { + title.text = t.name() + issues.text = numberFormat.format(t.issues().totalCount()) + pullRequest.text = numberFormat.format(t.pullRequests().totalCount()) + forks.text = numberFormat.format(t.forks().totalCount()) + stars.text = numberFormat.format(t.stargazers().totalCount()) + t.primaryLanguage()?.let { + language.text = it.name() + it.color()?.let { + if (it.startsWith("#")) { + language.tintDrawables(Color.parseColor(it)) + } else { + val color = "#$it" + language.tintDrawables(Color.parseColor(color)) + } + } + } + } + + companion object { + fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>): ProfilePinnedReposViewHolder { + return ProfilePinnedReposViewHolder(getView(parent, R.layout.profile_pinned_repo_row_item), adapter) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestDetailsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestDetailsViewHolder.java new file mode 100644 index 00000000..548c5362 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestDetailsViewHolder.java @@ -0,0 +1,285 @@ +package com.fastaccess.ui.adapter.viewholder; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.transition.ChangeBounds; +import android.support.transition.TransitionManager; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.fastaccess.R; +import com.fastaccess.data.dao.ReactionsModel; +import com.fastaccess.data.dao.model.Issue; +import com.fastaccess.data.dao.model.PullRequest; +import com.fastaccess.data.dao.model.User; +import com.fastaccess.data.dao.timeline.PullRequestTimelineModel; +import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.ParseDateFormat; +import com.fastaccess.provider.scheme.LinkParserHelper; +import com.fastaccess.provider.timeline.CommentsHelper; +import com.fastaccess.provider.timeline.HtmlHelper; +import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter; +import com.fastaccess.ui.adapter.callback.OnToggleView; +import com.fastaccess.ui.adapter.callback.ReactionsCallback; +import com.fastaccess.ui.widgets.AvatarLayout; +import com.fastaccess.ui.widgets.FontTextView; +import com.fastaccess.ui.widgets.SpannableBuilder; +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter; +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; + +import java.util.Date; + +import butterknife.BindView; + +/** + * Created by Kosh on 13 Dec 2016, 1:03 AM + */ + +public class PullRequestDetailsViewHolder extends BaseViewHolder { + + @BindView(R.id.avatarView) AvatarLayout avatar; + @BindView(R.id.date) FontTextView date; + @BindView(R.id.name) FontTextView name; + @BindView(R.id.comment) FontTextView comment; + @BindView(R.id.thumbsUp) FontTextView thumbsUp; + @BindView(R.id.thumbsDown) FontTextView thumbsDown; + @BindView(R.id.laugh) FontTextView laugh; + @BindView(R.id.sad) FontTextView sad; + @BindView(R.id.hurray) FontTextView hooray; + @BindView(R.id.heart) FontTextView heart; + @BindView(R.id.toggle) View toggle; + @BindView(R.id.commentMenu) View commentMenu; + @BindView(R.id.commentOptions) View commentOptions; + @BindView(R.id.toggleHolder) View toggleHolder; + @BindView(R.id.emojiesList) View emojiesList; + @BindView(R.id.reactionsText) TextView reactionsText; + @BindView(R.id.owner) TextView owner; + private OnToggleView onToggleView; + private ReactionsCallback reactionsCallback; + private ViewGroup viewGroup; + private String repoOwner; + private String poster; + + private PullRequestDetailsViewHolder(@NonNull View itemView, @NonNull ViewGroup viewGroup, @Nullable BaseRecyclerAdapter adapter, + @NonNull OnToggleView onToggleView, @NonNull ReactionsCallback reactionsCallback, + String repoOwner, String poster) { + super(itemView, adapter); + this.onToggleView = onToggleView; + this.viewGroup = viewGroup; + this.reactionsCallback = reactionsCallback; + this.repoOwner = repoOwner; + this.poster = poster; + itemView.setOnClickListener(null); + itemView.setOnLongClickListener(null); + commentMenu.setOnClickListener(this); + toggle.setOnClickListener(this); + toggleHolder.setOnClickListener(this); + laugh.setOnClickListener(this); + sad.setOnClickListener(this); + thumbsDown.setOnClickListener(this); + thumbsUp.setOnClickListener(this); + hooray.setOnClickListener(this); + laugh.setOnLongClickListener(this); + sad.setOnLongClickListener(this); + thumbsDown.setOnLongClickListener(this); + thumbsUp.setOnLongClickListener(this); + hooray.setOnLongClickListener(this); + heart.setOnLongClickListener(this); + heart.setOnClickListener(this); + } + + public static PullRequestDetailsViewHolder newInstance(@NonNull ViewGroup viewGroup, @Nullable BaseRecyclerAdapter adapter, + @NonNull OnToggleView onToggleView, @NonNull ReactionsCallback reactionsCallback, + @NonNull String repoOwner, @NonNull String poster) { + return new PullRequestDetailsViewHolder(getView(viewGroup, R.layout.issue_detail_header_row_item), viewGroup, + adapter, onToggleView, reactionsCallback, repoOwner, poster); + } + + @Override public void bind(@NonNull PullRequestTimelineModel timelineModel) { + if (timelineModel.getPullRequest() != null) { + bind(timelineModel.getPullRequest()); + } + if (onToggleView != null) onToggle(onToggleView.isCollapsed(getAdapterPosition()), false); + } + + @Override public void onClick(View v) { + if (v.getId() == R.id.toggle || v.getId() == R.id.toggleHolder) { + if (onToggleView != null) { + int position = getAdapterPosition(); + onToggleView.onToggle(position, !onToggleView.isCollapsed(position)); + onToggle(onToggleView.isCollapsed(position), true); + } + } else { + addReactionCount(v); + super.onClick(v); + } + } + + private void addReactionCount(View v) { + if (adapter != null) { + PullRequestTimelineModel timelineModel = (PullRequestTimelineModel) adapter.getItem(getAdapterPosition()); + if (timelineModel == null) return; + ReactionsModel reactionsModel = null; + PullRequest pullRequest = timelineModel.getPullRequest(); + int number = 0; + if (pullRequest != null) { + reactionsModel = pullRequest.getReactions(); + number = pullRequest.getNumber(); + } + if (reactionsModel == null) reactionsModel = new ReactionsModel(); + boolean isReacted = reactionsCallback == null || reactionsCallback.isPreviouslyReacted(number, v.getId()); + boolean isCallingApi = reactionsCallback != null && reactionsCallback.isCallingApi(number, v.getId()); + switch (v.getId()) { + case R.id.heart: + reactionsModel.setHeart(!isReacted ? reactionsModel.getHeart() + 1 : reactionsModel.getHeart() - 1); + break; + case R.id.sad: + reactionsModel.setConfused(!isReacted ? reactionsModel.getConfused() + 1 : reactionsModel.getConfused() - 1); + break; + case R.id.thumbsDown: + reactionsModel.setMinusOne(!isReacted ? reactionsModel.getMinusOne() + 1 : reactionsModel.getMinusOne() - 1); + break; + case R.id.thumbsUp: + reactionsModel.setPlusOne(!isReacted ? reactionsModel.getPlusOne() + 1 : reactionsModel.getPlusOne() - 1); + break; + case R.id.laugh: + reactionsModel.setLaugh(!isReacted ? reactionsModel.getLaugh() + 1 : reactionsModel.getLaugh() - 1); + break; + case R.id.hurray: + reactionsModel.setHooray(!isReacted ? reactionsModel.getHooray() + 1 : reactionsModel.getHooray() - 1); + break; + } + if (pullRequest != null) { + pullRequest.setReactions(reactionsModel); + appendEmojies(reactionsModel); + timelineModel.setPullRequest(pullRequest); + } + } + } + + private void bind(@NonNull Issue issueModel) { + setup(issueModel.getUser(), issueModel.getBodyHtml(), issueModel.getReactions()); + setupDate(issueModel.getCreatedAt(), issueModel.getUpdatedAt()); + } + + private void bind(@NonNull PullRequest pullRequest) { + setup(pullRequest.getUser(), pullRequest.getBodyHtml(), pullRequest.getReactions()); + setupDate(pullRequest.getCreatedAt(), pullRequest.getUpdatedAt()); + } + + private void setup(User user, String description, ReactionsModel reactionsModel) { + avatar.setUrl(user.getAvatarUrl(), user.getLogin(), user.isOrganizationType(), LinkParserHelper.isEnterprise(user.getHtmlUrl())); + name.setText(user.getLogin()); + boolean isOwner = TextUtils.equals(repoOwner, user.getLogin()); + if (isOwner) { + owner.setVisibility(View.VISIBLE); + owner.setText(R.string.owner); + } else { + owner.setText(null); + owner.setVisibility(View.GONE); + } + if (reactionsModel != null) { + appendEmojies(reactionsModel); + } + if (description != null && !description.trim().isEmpty()) { + HtmlHelper.htmlIntoTextView(comment, description, viewGroup.getWidth()); + } else { + comment.setText(R.string.no_description_provided); + } + } + + private void setupDate(@NonNull Date createdDate, @NonNull Date updated) { + date.setText(ParseDateFormat.getTimeAgo(createdDate)); + } + + private void appendEmojies(@NonNull ReactionsModel reaction) { + SpannableBuilder spannableBuilder = SpannableBuilder.builder(); + reactionsText.setText(""); + thumbsUp.setText(SpannableBuilder.builder() + .append(CommentsHelper.getThumbsUp()).append(" ") + .append(String.valueOf(reaction.getPlusOne())) + .append(" ")); + thumbsDown.setText(SpannableBuilder.builder() + .append(CommentsHelper.getThumbsDown()).append(" ") + .append(String.valueOf(reaction.getMinusOne())) + .append(" ")); + hooray.setText(SpannableBuilder.builder() + .append(CommentsHelper.getHooray()).append(" ") + .append(String.valueOf(reaction.getHooray())) + .append(" ")); + sad.setText(SpannableBuilder.builder() + .append(CommentsHelper.getSad()).append(" ") + .append(String.valueOf(reaction.getConfused())) + .append(" ")); + laugh.setText(SpannableBuilder.builder() + .append(CommentsHelper.getLaugh()).append(" ") + .append(String.valueOf(reaction.getLaugh())) + .append(" ")); + heart.setText(SpannableBuilder.builder() + .append(CommentsHelper.getHeart()).append(" ") + .append(String.valueOf(reaction.getHeart()))); + if (reaction.getPlusOne() > 0) { + spannableBuilder.append(CommentsHelper.getThumbsUp()) + .append(" ") + .append(String.valueOf(reaction.getPlusOne())) + .append(" "); + } + if (reaction.getMinusOne() > 0) { + spannableBuilder.append(CommentsHelper.getThumbsDown()) + .append(" ") + .append(String.valueOf(reaction.getMinusOne())) + .append(" "); + } + if (reaction.getLaugh() > 0) { + spannableBuilder.append(CommentsHelper.getLaugh()) + .append(" ") + .append(String.valueOf(reaction.getLaugh())) + .append(" "); + } + if (reaction.getHooray() > 0) { + spannableBuilder.append(CommentsHelper.getHooray()) + .append(" ") + .append(String.valueOf(reaction.getHooray())) + .append(" "); + } + if (reaction.getConfused() > 0) { + spannableBuilder.append(CommentsHelper.getSad()) + .append(" ") + .append(String.valueOf(reaction.getConfused())) + .append(" "); + } + if (reaction.getHeart() > 0) { + spannableBuilder.append(CommentsHelper.getHeart()) + .append(" ") + .append(String.valueOf(reaction.getHeart())); + } + if (spannableBuilder.length() > 0) { + reactionsText.setText(spannableBuilder); + if (!onToggleView.isCollapsed(getAdapterPosition())) { + reactionsText.setVisibility(View.VISIBLE); + } + } else { + reactionsText.setVisibility(View.GONE); + } + } + + private void onToggle(boolean expanded, boolean animate) { + if (animate) { + TransitionManager.beginDelayedTransition(viewGroup, new ChangeBounds()); + } + toggle.setRotation(!expanded ? 0.0F : 180F); + commentOptions.setVisibility(!expanded ? View.GONE : View.VISIBLE); + if (!InputHelper.isEmpty(reactionsText)) { + reactionsText.setVisibility(!expanded ? View.VISIBLE : View.GONE); + } + } + + @Override protected void onViewIsDetaching() { + DrawableGetter drawableGetter = (DrawableGetter) comment.getTag(R.id.drawable_callback); + if (drawableGetter != null) { + drawableGetter.clear(drawableGetter); + } + } +} diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt new file mode 100644 index 00000000..c6f1d8ea --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt @@ -0,0 +1,414 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.annotation.SuppressLint +import android.graphics.Color +import android.support.v4.content.ContextCompat +import android.text.style.BackgroundColorSpan +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.data.dao.timeline.PullRequestTimelineModel +import com.fastaccess.helper.ParseDateFormat +import com.fastaccess.helper.PrefGetter +import com.fastaccess.helper.ViewHelper +import com.fastaccess.provider.scheme.LinkParserHelper +import com.fastaccess.provider.timeline.HtmlHelper +import com.fastaccess.ui.widgets.AvatarLayout +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.ForegroundImageView +import com.fastaccess.ui.widgets.SpannableBuilder +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder +import com.zzhoujay.markdown.style.CodeSpan +import pr.PullRequestTimelineQuery +import pr.type.StatusState + +/** + * Created by kosh on 03/08/2017. + */ + +class PullRequestEventViewHolder private constructor(view: View, adapter: BaseRecyclerAdapter<*, *, *>) : + BaseViewHolder(view, adapter) { + + @BindView(R.id.stateImage) lateinit var stateImage: ForegroundImageView + @BindView(R.id.avatarLayout) lateinit var avatarLayout: AvatarLayout + @BindView(R.id.stateText) lateinit var stateText: FontTextView + @BindView(R.id.commitStatus) lateinit var commitStatus: ForegroundImageView + + override fun bind(t: PullRequestTimelineModel) { + val node = t.node + commitStatus.visibility = View.GONE + if (node != null) { + when { + node.asAssignedEvent() != null -> assignedEvent(node.asAssignedEvent()!!) + node.asBaseRefForcePushedEvent() != null -> forcePushEvent(node.asBaseRefForcePushedEvent()!!) + node.asClosedEvent() != null -> closedEvent(node.asClosedEvent()!!) + node.asCommit() != null -> commitEvent(node.asCommit()!!) + node.asDemilestonedEvent() != null -> demilestonedEvent(node.asDemilestonedEvent()!!) + node.asDeployedEvent() != null -> deployedEvent(node.asDeployedEvent()!!) + node.asHeadRefDeletedEvent() != null -> refDeletedEvent(node.asHeadRefDeletedEvent()!!) + node.asHeadRefForcePushedEvent() != null -> refForPushedEvent(node.asHeadRefForcePushedEvent()!!) + node.asHeadRefRestoredEvent() != null -> headRefRestoredEvent(node.asHeadRefRestoredEvent()!!) + node.asLabeledEvent() != null -> labeledEvent(node.asLabeledEvent()!!) + node.asLockedEvent() != null -> lockEvent(node.asLockedEvent()!!) + node.asMergedEvent() != null -> mergedEvent(node.asMergedEvent()!!) + node.asMilestonedEvent() != null -> milestoneEvent(node.asMilestonedEvent()!!) + node.asReferencedEvent() != null -> referenceEvent(node.asReferencedEvent()!!) + node.asRenamedTitleEvent() != null -> renamedEvent(node.asRenamedTitleEvent()!!) + node.asReopenedEvent() != null -> reopenedEvent(node.asReopenedEvent()!!) + node.asUnassignedEvent() != null -> unassignedEvent(node.asUnassignedEvent()!!) + node.asUnlabeledEvent() != null -> unlabeledEvent(node.asUnlabeledEvent()!!) + node.asUnlockedEvent() != null -> unlockedEvent(node.asUnlockedEvent()!!) + else -> reset() + } + } else { + reset() + } + } + + private fun reset() { + stateText.text = null + avatarLayout.setUrl(null, null, false, false) + } + + @SuppressLint("SetTextI18n") + private fun unlockedEvent(event: PullRequestTimelineQuery.AsUnlockedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("unlocked this conversation") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_lock) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun unlabeledEvent(event: PullRequestTimelineQuery.AsUnlabeledEvent) { + event.actor()?.let { + val color = Color.parseColor("#" + event.label().color()) + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("removed") + .append(" ") + .append(event.label().name(), CodeSpan(color, ViewHelper.generateTextColor(color), 5.0f)) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_label) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun unassignedEvent(event: PullRequestTimelineQuery.AsUnassignedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("unassigned") //TODO add "removed their assignment" for self + .append(" ") + .append(event.user()?.login()) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_profile) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun reopenedEvent(event: PullRequestTimelineQuery.AsReopenedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("reopened this") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_issue_opened) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun renamedEvent(event: PullRequestTimelineQuery.AsRenamedTitleEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("changed the title from").append(" ").append(event.previousTitle()) + .append(" ").append("to").append(" ").bold(event.currentTitle()) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_edit) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun referenceEvent(event: PullRequestTimelineQuery.AsReferencedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append(if (event.isCrossRepository) "cross referenced this" else "referenced this") + .append(" ") + .append("from").append(" ") + .url(if (event.commit() != null) { + substring(event.commit()?.oid()?.toString()) + } else if (event.subject().asIssue() != null) { + if (event.isCrossRepository) { + "${event.commitRepository().nameWithOwner()} ${event.subject().asIssue()?.title()}#${event.subject().asIssue()?.number()}" + } else { + "${event.subject().asIssue()?.title()}#${event.subject().asIssue()?.number()}" + } + } else if (event.subject().asPullRequest() != null) { + if (event.isCrossRepository) { + "${event.commitRepository().nameWithOwner()} ${event.subject().asPullRequest()?.title()}" + + "#${event.subject().asPullRequest()?.number()}" + } else { + "${event.subject().asPullRequest()?.title()}#${event.subject().asPullRequest()?.number()}" + } + } else { + event.commitRepository().nameWithOwner() + }) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_push) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun milestoneEvent(event: PullRequestTimelineQuery.AsMilestonedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("added this to the") + .append(" ") + .append(event.milestoneTitle()).append(" ").append("milestone") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_milestone) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun mergedEvent(event: PullRequestTimelineQuery.AsMergedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("merged commit") + .append(" ") + .url(substring(event.commit()?.oid()?.toString())) + .append(" ") + .append("into") + .append(" ") + .append(event.actor()) + .append(":") + .append(event.mergeRefName(), BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_merge) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun lockEvent(event: PullRequestTimelineQuery.AsLockedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("locked and limited conversation to collaborators") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_lock) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun labeledEvent(event: PullRequestTimelineQuery.AsLabeledEvent) { + event.actor()?.let { + val color = Color.parseColor("#" + event.label().color()) + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("labeled") + .append(" ") + .append(event.label().name(), CodeSpan(color, ViewHelper.generateTextColor(color), 5.0f)) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_label) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun headRefRestoredEvent(event: PullRequestTimelineQuery.AsHeadRefRestoredEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("restored the") + .append(" ") + .append(it.login()) + .append(":") + .append(event.pullRequest().headRefName(), BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))) + .append(" ") + .append("branch") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_push) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun refForPushedEvent(event: PullRequestTimelineQuery.AsHeadRefForcePushedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("reference force pushed to", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))) + .append(" ") + .url(substring(event.afterCommit().oid().toString())) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_push) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun refDeletedEvent(event: PullRequestTimelineQuery.AsHeadRefDeletedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("deleted the") + .append(" ") + .append(it.login()) + .append(":") + .append(substring(event.headRefName()), BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))) + .append(" ") + .append("branch") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_trash) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun deployedEvent(event: PullRequestTimelineQuery.AsDeployedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("made a deployment", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))) + .append(" ") + .append(event.deployment().latestStatus()?.state()?.name) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_push) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun demilestonedEvent(event: PullRequestTimelineQuery.AsDemilestonedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("removed this from the") + .append(" ") + .append(event.milestoneTitle()).append(" ").append("milestone") + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_milestone) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun commitEvent(event: PullRequestTimelineQuery.AsCommit) { + event.author()?.let { + stateText.text = SpannableBuilder.builder()//Review[k0shk0sh] We may want to suppress more then 3 or 4 commits. since it will clog the it + .bold(if (it.user() == null) it.name() else it.user()?.login()) + .append(" ") + .append("committed") + .append(" ") + .append(event.messageHeadline()) + .append(" ") + .url(substring(event.oid().toString())) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.committedDate().toString()))) + stateImage.setImageResource(R.drawable.ic_push) + avatarLayout.setUrl(it.user()?.avatarUrl().toString(), it.user()?.login(), false, + LinkParserHelper.isEnterprise(it.user()?.url().toString())) + event.status()?.let { + commitStatus.visibility = View.VISIBLE + val context = commitStatus.context + commitStatus.tintDrawableColor(when (it.state()) { + StatusState.ERROR -> ContextCompat.getColor(context, R.color.material_red_700) + StatusState.FAILURE -> ContextCompat.getColor(context, R.color.material_deep_orange_700) + StatusState.SUCCESS -> ContextCompat.getColor(context, R.color.material_green_700) + else -> ContextCompat.getColor(context, R.color.material_yellow_700) + }) + } + } + } + + private fun closedEvent(event: PullRequestTimelineQuery.AsClosedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("closed this in") + .append(" ") + .url(substring(event.commit()?.oid()?.toString())) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_merge) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun forcePushEvent(event: PullRequestTimelineQuery.AsBaseRefForcePushedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("force pushed to", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType()))) + .append(" ") + .url(substring(event.afterCommit().oid().toString())) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_push) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun assignedEvent(event: PullRequestTimelineQuery.AsAssignedEvent) { + event.actor()?.let { + stateText.text = SpannableBuilder.builder() + .bold(it.login()) + .append(" ") + .append("assigned") //TODO add "self-assigned" for self + .append(" ") + .append(event.user()?.login()) + .append(" ") + .append(ParseDateFormat.getTimeAgo((event.createdAt().toString()))) + stateImage.setImageResource(R.drawable.ic_profile) + avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString())) + } + } + + private fun substring(value: String?): String { + if (value == null) { + return "" + } + if (value.length <= 7) return value + else return value.substring(0, 7) + } + + companion object { + fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>): PullRequestEventViewHolder { + return PullRequestEventViewHolder(getView(parent, R.layout.issue_timeline_row_item), adapter) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestTimelineCommentsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestTimelineCommentsViewHolder.java new file mode 100644 index 00000000..36512e87 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestTimelineCommentsViewHolder.java @@ -0,0 +1,256 @@ +package com.fastaccess.ui.adapter.viewholder; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.transition.ChangeBounds; +import android.support.transition.TransitionManager; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; + +import com.fastaccess.R; +import com.fastaccess.data.dao.ReactionsModel; +import com.fastaccess.data.dao.timeline.PullRequestTimelineModel; +import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.ParseDateFormat; +import com.fastaccess.provider.scheme.LinkParserHelper; +import com.fastaccess.provider.timeline.CommentsHelper; +import com.fastaccess.provider.timeline.HtmlHelper; +import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter; +import com.fastaccess.ui.adapter.callback.OnToggleView; +import com.fastaccess.ui.widgets.AvatarLayout; +import com.fastaccess.ui.widgets.FontTextView; +import com.fastaccess.ui.widgets.ForegroundImageView; +import com.fastaccess.ui.widgets.SpannableBuilder; +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter; +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; + +import java.util.List; + +import butterknife.BindView; +import pr.PullRequestTimelineQuery; +import pr.type.ReactionContent; + +/** + * Created by Kosh on 11 Nov 2016, 2:08 PM + */ + +public class PullRequestTimelineCommentsViewHolder extends BaseViewHolder { + + + @BindView(R.id.avatarView) AvatarLayout avatar; + @BindView(R.id.name) FontTextView name; + @BindView(R.id.date) FontTextView date; + @BindView(R.id.toggle) ForegroundImageView toggle; + @BindView(R.id.commentMenu) ForegroundImageView commentMenu; + @BindView(R.id.toggleHolder) LinearLayout toggleHolder; + @BindView(R.id.thumbsUp) FontTextView thumbsUp; + @BindView(R.id.thumbsDown) FontTextView thumbsDown; + @BindView(R.id.laugh) FontTextView laugh; + @BindView(R.id.hurray) FontTextView hurray; + @BindView(R.id.sad) FontTextView sad; + @BindView(R.id.heart) FontTextView heart; + @BindView(R.id.emojiesList) HorizontalScrollView emojiesList; + @BindView(R.id.commentOptions) RelativeLayout commentOptions; + @BindView(R.id.comment) FontTextView comment; + @BindView(R.id.reactionsText) FontTextView reactionsText; + @BindView(R.id.owner) FontTextView owner; + private OnToggleView onToggleView; + private ViewGroup viewGroup; + + @Override public void onClick(View v) { + if (v.getId() == R.id.toggle || v.getId() == R.id.toggleHolder) { + if (onToggleView != null) { + int position = getAdapterPosition(); + onToggleView.onToggle(position, !onToggleView.isCollapsed(position)); + onToggle(onToggleView.isCollapsed(position), true); + } + } else { + addReactionCount(v); + super.onClick(v); + } + } + + private PullRequestTimelineCommentsViewHolder(@NonNull View itemView, @NonNull ViewGroup viewGroup, @Nullable BaseRecyclerAdapter adapter, + @NonNull OnToggleView onToggleView) { + super(itemView, adapter); + this.viewGroup = viewGroup; + this.onToggleView = onToggleView; + itemView.setOnClickListener(null); + itemView.setOnLongClickListener(null); + commentMenu.setOnClickListener(this); + commentMenu.setOnLongClickListener(this); + toggleHolder.setOnClickListener(this); + toggle.setOnClickListener(this); + laugh.setOnClickListener(this); + sad.setOnClickListener(this); + thumbsDown.setOnClickListener(this); + thumbsUp.setOnClickListener(this); + hurray.setOnClickListener(this); + laugh.setOnLongClickListener(this); + sad.setOnLongClickListener(this); + thumbsDown.setOnLongClickListener(this); + thumbsUp.setOnLongClickListener(this); + hurray.setOnLongClickListener(this); + heart.setOnLongClickListener(this); + heart.setOnClickListener(this); + } + + public static PullRequestTimelineCommentsViewHolder newInstance(@NonNull ViewGroup viewGroup, @Nullable BaseRecyclerAdapter adapter, + @NonNull OnToggleView onToggleView) { + return new PullRequestTimelineCommentsViewHolder(getView(viewGroup, R.layout.comments_row_item), viewGroup, adapter, onToggleView); + } + + @Override public void bind(@NonNull PullRequestTimelineModel timelineModel) { + PullRequestTimelineQuery.AsIssueComment commentsModel = timelineModel.getNode().asIssueComment(); + if (commentsModel != null) { + PullRequestTimelineQuery.Author4 author3 = commentsModel.author(); + owner.setVisibility(View.VISIBLE); + owner.setText("none".equalsIgnoreCase(commentsModel.authorAssociation().name().toLowerCase()) + ? "" : commentsModel.authorAssociation().name().toLowerCase()); + if (author3 != null) { + avatar.setUrl(author3.avatarUrl().toString(), author3.login(), + false, LinkParserHelper.isEnterprise(author3.url().toString())); + name.setText(author3.login()); + } else { + avatar.setUrl(null, null, false, false); + name.setText(null); + } + if (!InputHelper.isEmpty(commentsModel.bodyHTML())) { + String body = commentsModel.bodyHTML().toString(); + HtmlHelper.htmlIntoTextView(comment, body, viewGroup.getWidth()); + } else { + comment.setText(""); + } + if (commentsModel.createdAt().equals(commentsModel.lastEditedAt())) { + date.setText(String.format("%s %s", ParseDateFormat.getTimeAgo(commentsModel.lastEditedAt().toString()), itemView + .getResources().getString(R.string.edited))); + } else { + date.setText(ParseDateFormat.getTimeAgo(commentsModel.createdAt().toString())); + } + appendEmojies(timelineModel.getReactions()); + emojiesList.setVisibility(View.VISIBLE); + if (onToggleView != null) onToggle(onToggleView.isCollapsed(getAdapterPosition()), false); + } + } + + private void addReactionCount(View v) { + if (adapter != null) { + PullRequestTimelineModel timelineModel = (PullRequestTimelineModel) adapter.getItem(getAdapterPosition()); + if (timelineModel == null) return; + List reactions = timelineModel.getReactions(); + if (reactions != null && !reactions.isEmpty()) { + int reactionIndex = getReaction(v.getId(), reactions); + if (reactionIndex != -1) { + ReactionsModel reaction = reactions.get(reactionIndex); + if (!reaction.isViewerHasReacted()) { + reaction.setViewerHasReacted(true); + reaction.setTotal_count(reaction.getTotal_count() + 1); + } else { + reaction.setViewerHasReacted(false); + reaction.setTotal_count(reaction.getTotal_count() - 1); + } + reactions.set(reactionIndex, reaction); + } + appendEmojies(reactions); + timelineModel.setReactions(reactions); + } + } + } + + private int getReaction(int id, @NonNull List reactionGroup) { + for (int i = 0; i < reactionGroup.size(); i++) { + ReactionsModel reactionGroup1 = reactionGroup.get(i); + if (id == R.id.heart && reactionGroup1.getContent().equalsIgnoreCase(ReactionContent.HEART.name())) { + return i; + } else if (id == R.id.sad && reactionGroup1.getContent().equalsIgnoreCase(ReactionContent.CONFUSED.name())) { + return i; + } else if (id == R.id.hurray && reactionGroup1.getContent().equalsIgnoreCase(ReactionContent.HOORAY.name())) { + return i; + } else if (id == R.id.laugh && reactionGroup1.getContent().equalsIgnoreCase(ReactionContent.LAUGH.name())) { + return i; + } else if (id == R.id.thumbsDown && reactionGroup1.getContent().equalsIgnoreCase(ReactionContent.THUMBS_DOWN.name())) { + return i; + } else if (id == R.id.thumbsUp && reactionGroup1.getContent().equalsIgnoreCase(ReactionContent.THUMBS_UP.name())) { + return i; + } + } + return -1; + } + + private void appendEmojies(@NonNull List reactions) { + reactionsText.setText(""); + SpannableBuilder spannableBuilder = SpannableBuilder.builder(); + for (ReactionsModel reaction : reactions) { + CharSequence charSequence = null; + if (reaction.getContent().equalsIgnoreCase(ReactionContent.THUMBS_UP.name())) { + charSequence = SpannableBuilder.builder() + .append(CommentsHelper.getThumbsUp()).append(" ") + .append(String.valueOf(reaction.getTotal_count())) + .append(" "); + thumbsUp.setText(charSequence); + } else if (reaction.getContent().equalsIgnoreCase(ReactionContent.THUMBS_DOWN.name())) { + charSequence = SpannableBuilder.builder() + .append(CommentsHelper.getThumbsDown()).append(" ") + .append(String.valueOf(reaction.getTotal_count())) + .append(" "); + thumbsDown.setText(charSequence); + } else if (reaction.getContent().equalsIgnoreCase(ReactionContent.LAUGH.name())) { + charSequence = SpannableBuilder.builder() + .append(CommentsHelper.getLaugh()).append(" ") + .append(String.valueOf(reaction.getTotal_count())) + .append(" "); + laugh.setText(charSequence); + } else if (reaction.getContent().equalsIgnoreCase(ReactionContent.HOORAY.name())) { + charSequence = SpannableBuilder.builder() + .append(CommentsHelper.getHooray()).append(" ") + .append(String.valueOf(reaction.getTotal_count())) + .append(" "); + hurray.setText(charSequence); + } else if (reaction.getContent().equalsIgnoreCase(ReactionContent.HEART.name())) { + charSequence = SpannableBuilder.builder() + .append(CommentsHelper.getHeart()).append(" ") + .append(String.valueOf(reaction.getTotal_count())) + .append(" "); + heart.setText(charSequence); + } else if (reaction.getContent().equalsIgnoreCase(ReactionContent.CONFUSED.name())) { + charSequence = SpannableBuilder.builder() + .append(CommentsHelper.getSad()).append(" ") + .append(String.valueOf(reaction.getTotal_count())) + .append(" "); + sad.setText(charSequence); + } + if (charSequence != null && reaction.getTotal_count() > 0) { + spannableBuilder.append(charSequence); + } + } + if (spannableBuilder.length() > 0) { + reactionsText.setText(spannableBuilder); + if (!onToggleView.isCollapsed(getAdapterPosition())) { + reactionsText.setVisibility(View.VISIBLE); + } + } else { + reactionsText.setVisibility(View.GONE); + } + } + + private void onToggle(boolean expanded, boolean animate) { + if (animate) { + TransitionManager.beginDelayedTransition(viewGroup, new ChangeBounds()); + } + toggle.setRotation(!expanded ? 0.0F : 180F); + commentOptions.setVisibility(!expanded ? View.GONE : View.VISIBLE); + if (!InputHelper.isEmpty(reactionsText)) { + reactionsText.setVisibility(!expanded ? View.VISIBLE : View.GONE); + } + } + + @Override protected void onViewIsDetaching() { + DrawableGetter drawableGetter = (DrawableGetter) comment.getTag(R.id.drawable_callback); + if (drawableGetter != null) { + drawableGetter.clear(drawableGetter); + } + } +} diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullStatusViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullStatusViewHolder.java index 1837a9fb..0ba3815f 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullStatusViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullStatusViewHolder.java @@ -1,6 +1,5 @@ package com.fastaccess.ui.adapter.viewholder; -import android.net.Uri; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.text.method.LinkMovementMethod; @@ -78,6 +77,7 @@ public class PullStatusViewHolder extends BaseViewHolder builder.append(ContextCompat.getDrawable(statuses.getContext(), statusesModel.getState().getDrawableRes())); if (!InputHelper.isEmpty(statusesModel.getTargetUrl())) { builder.append(" ") + .append(statusesModel.getContext() != null ? statusesModel.getContext() + " " : "") .url(statusesModel.getDescription(), v -> SchemeParser.launchUri(v.getContext(), statusesModel.getTargetUrl())) .append("\n"); } else { diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewCommentsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewCommentsViewHolder.java index 1085675a..5753b250 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewCommentsViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewCommentsViewHolder.java @@ -31,10 +31,6 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; import butterknife.BindView; -/** - * Created by Kosh on 15 Feb 2017, 10:29 PM - */ - public class ReviewCommentsViewHolder extends BaseViewHolder { @BindView(R.id.avatarView) AvatarLayout avatarView; @@ -129,7 +125,7 @@ public class ReviewCommentsViewHolder extends BaseViewHolder } date.setText(ParseDateFormat.getTimeAgo(commentModel.getCreatedAt())); if (!InputHelper.isEmpty(commentModel.getBodyHtml())) { - HtmlHelper.htmlIntoTextView(comment, commentModel.getBodyHtml()); + HtmlHelper.htmlIntoTextView(comment, commentModel.getBodyHtml(), viewGroup.getWidth()); } else { comment.setText(""); } @@ -268,4 +264,4 @@ public class ReviewCommentsViewHolder extends BaseViewHolder drawableGetter.clear(drawableGetter); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewsViewHolder.java deleted file mode 100644 index bba23357..00000000 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewsViewHolder.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.fastaccess.ui.adapter.viewholder; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.View; -import android.view.ViewGroup; - -import com.fastaccess.R; -import com.fastaccess.data.dao.ReviewModel; -import com.fastaccess.data.dao.TimelineModel; -import com.fastaccess.helper.InputHelper; -import com.fastaccess.helper.ParseDateFormat; -import com.fastaccess.provider.scheme.LinkParserHelper; -import com.fastaccess.provider.timeline.HtmlHelper; -import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter; -import com.fastaccess.ui.widgets.AvatarLayout; -import com.fastaccess.ui.widgets.FontTextView; -import com.fastaccess.ui.widgets.ForegroundImageView; -import com.fastaccess.ui.widgets.SpannableBuilder; -import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter; -import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; - -import butterknife.BindView; - -/** - * Created by Kosh on 13 Dec 2016, 1:42 AM - */ - -public class ReviewsViewHolder extends BaseViewHolder { - - @BindView(R.id.stateImage) ForegroundImageView stateImage; - @BindView(R.id.avatarLayout) AvatarLayout avatarLayout; - @BindView(R.id.stateText) FontTextView stateText; - @BindView(R.id.body) FontTextView body; - - private ReviewsViewHolder(@NonNull View itemView, @Nullable BaseRecyclerAdapter adapter) { - super(itemView, adapter); - itemView.setOnLongClickListener(null); - itemView.setOnClickListener(null); - } - - public static ReviewsViewHolder newInstance(ViewGroup viewGroup, BaseRecyclerAdapter adapter) { - return new ReviewsViewHolder(getView(viewGroup, R.layout.review_timeline_row_item), adapter); - } - - @Override public void bind(@NonNull TimelineModel model) { - ReviewModel review = model.getReview(); - if (review != null) { - if (review.getUser() != null) { - avatarLayout.setUrl(review.getUser().getAvatarUrl(), review.getUser().getLogin(), false, - LinkParserHelper.isEnterprise(review.getUser().getHtmlUrl())); - } else { - avatarLayout.setUrl(null, null, false, false); - } - if (review.getState() != null) { - stateImage.setImageResource(review.getState().getDrawableRes()); - } - if (review.getUser() != null) { - stateText.setText(SpannableBuilder.builder().append(review.getUser().getLogin()) - .append(" ") - .append(review.getState() != null ? stateText.getResources().getString(review.getState().getStringRes()) : "") - .append(" ") - .append(ParseDateFormat.getTimeAgo(review.getSubmittedAt()))); - } - if (!InputHelper.isEmpty(review.getBody())) { - body.setVisibility(View.VISIBLE); - HtmlHelper.htmlIntoTextView(body, review.getBody()); - } else { - body.setVisibility(View.GONE); - } - } - } - - @Override protected void onViewIsDetaching() { - DrawableGetter drawableGetter = (DrawableGetter) stateText.getTag(R.id.drawable_callback); - if (drawableGetter != null) { - drawableGetter.clear(drawableGetter); - } - } -} diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewsViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewsViewHolder.kt new file mode 100644 index 00000000..79d18243 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/ReviewsViewHolder.kt @@ -0,0 +1,62 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.data.dao.TimelineModel +import com.fastaccess.data.dao.types.IssueEventType +import com.fastaccess.helper.ParseDateFormat +import com.fastaccess.provider.timeline.HtmlHelper +import com.fastaccess.ui.widgets.AvatarLayout +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.ForegroundImageView +import com.fastaccess.ui.widgets.SpannableBuilder +import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by Kosh on 13 Dec 2016, 1:42 AM + */ + +class ReviewsViewHolder private constructor(itemView: View, + adapter: BaseRecyclerAdapter<*, *, *>?, + val viewGroup: ViewGroup) : BaseViewHolder(itemView, adapter) { + + @BindView(R.id.stateImage) lateinit var stateImage: ForegroundImageView + @BindView(R.id.avatarLayout) lateinit var avatarLayout: AvatarLayout + @BindView(R.id.stateText) lateinit var stateText: FontTextView + @BindView(R.id.body) lateinit var body: FontTextView + + init { + itemView.setOnLongClickListener(null) + itemView.setOnClickListener(null) + } + + override fun bind(model: TimelineModel) { + val review = model.review + review?.let { + stateImage.setImageResource(R.drawable.ic_eye) + avatarLayout.setUrl(it.user?.avatarUrl, it.user?.login, false, false) + stateText.text = SpannableBuilder.builder().bold(if (it.user != null) { + it.user.login + } else { + "" + }).append(" ${if (model.event == IssueEventType.reviewed) "reviewed" else "requested changes"} ").append(ParseDateFormat.getTimeAgo(it.submittedAt)) + if (!it.bodyHtml.isNullOrBlank()) { + HtmlHelper.htmlIntoTextView(body, it.bodyHtml, viewGroup.width) + body.visibility = View.VISIBLE + } else { + body.text = "" + body.visibility = View.GONE + } + } + } + + companion object { + fun newInstance(viewGroup: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>): ReviewsViewHolder { + return ReviewsViewHolder(BaseViewHolder.getView(viewGroup, R.layout.review_timeline_row_item), adapter, viewGroup) + } + } + +} diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TimelineCommentsViewHolder.java b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TimelineCommentsViewHolder.java index 7edd793f..bf92290e 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TimelineCommentsViewHolder.java +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TimelineCommentsViewHolder.java @@ -21,7 +21,7 @@ import com.fastaccess.provider.scheme.LinkParserHelper; import com.fastaccess.provider.timeline.CommentsHelper; import com.fastaccess.provider.timeline.HtmlHelper; import com.fastaccess.provider.timeline.handler.drawable.DrawableGetter; -import com.fastaccess.ui.adapter.IssuePullsTimelineAdapter; +import com.fastaccess.ui.adapter.IssuesTimelineAdapter; import com.fastaccess.ui.adapter.callback.OnToggleView; import com.fastaccess.ui.adapter.callback.ReactionsCallback; import com.fastaccess.ui.widgets.AvatarLayout; @@ -56,6 +56,7 @@ public class TimelineCommentsViewHolder extends BaseViewHolder { @BindView(R.id.comment) FontTextView comment; @BindView(R.id.reactionsText) FontTextView reactionsText; @BindView(R.id.owner) FontTextView owner; + @BindView(R.id.pathText) FontTextView pathText; private OnToggleView onToggleView; private boolean showEmojies; private ReactionsCallback reactionsCallback; @@ -76,7 +77,7 @@ public class TimelineCommentsViewHolder extends BaseViewHolder { } } - private TimelineCommentsViewHolder(@NonNull View itemView, @NonNull ViewGroup viewGroup, @Nullable IssuePullsTimelineAdapter adapter, + private TimelineCommentsViewHolder(@NonNull View itemView, @NonNull ViewGroup viewGroup, @Nullable IssuesTimelineAdapter adapter, @NonNull OnToggleView onToggleView, boolean showEmojies, @NonNull ReactionsCallback reactionsCallback, String repoOwner, String poster) { super(itemView, adapter); @@ -89,6 +90,7 @@ public class TimelineCommentsViewHolder extends BaseViewHolder { itemView.setOnClickListener(null); itemView.setOnLongClickListener(null); commentMenu.setOnClickListener(this); + commentMenu.setOnLongClickListener(this); toggleHolder.setOnClickListener(this); toggle.setOnClickListener(this); laugh.setOnClickListener(this); @@ -105,7 +107,7 @@ public class TimelineCommentsViewHolder extends BaseViewHolder { heart.setOnClickListener(this); } - public static TimelineCommentsViewHolder newInstance(@NonNull ViewGroup viewGroup, @Nullable IssuePullsTimelineAdapter adapter, + public static TimelineCommentsViewHolder newInstance(@NonNull ViewGroup viewGroup, @Nullable IssuesTimelineAdapter adapter, @NonNull OnToggleView onToggleView, boolean showEmojies, @NonNull ReactionsCallback reactionsCallback, String repoOwner, String poster) { return new TimelineCommentsViewHolder(getView(viewGroup, R.layout.comments_row_item), viewGroup, adapter, @@ -136,14 +138,17 @@ public class TimelineCommentsViewHolder extends BaseViewHolder { avatar.setUrl(null, null, false, false); name.setText(null); } + if (!InputHelper.isEmpty(commentsModel.getPath()) && commentsModel.getPosition() > 0) { + pathText.setVisibility(View.VISIBLE); + pathText.setText(String.format("Commented on %s#L%s", commentsModel.getPath(), + commentsModel.getLine() > 0 ? commentsModel.getLine() : commentsModel.getPosition())); + } else { + pathText.setText(""); + pathText.setVisibility(View.GONE); + } if (!InputHelper.isEmpty(commentsModel.getBodyHtml())) { String body = commentsModel.getBodyHtml(); - if (!InputHelper.isEmpty(commentsModel.getPath()) && commentsModel.getPosition() > 0) { - body = "Commented at line(" + - (commentsModel.getLine() > 0 ? commentsModel.getLine() : commentsModel.getPosition()) + ") in " - + commentsModel.getPath() + "
" + body; - } - HtmlHelper.htmlIntoTextView(comment, body); + HtmlHelper.htmlIntoTextView(comment, body, viewGroup.getWidth()); } else { comment.setText(""); } diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TrendingViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TrendingViewHolder.kt index 8f4e8ed8..c55acee1 100644 --- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TrendingViewHolder.kt +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/TrendingViewHolder.kt @@ -1,13 +1,13 @@ package com.fastaccess.ui.adapter.viewholder import android.view.View +import butterknife.BindView import com.fastaccess.R import com.fastaccess.data.dao.TrendingModel import com.fastaccess.helper.Logger import com.fastaccess.provider.colors.ColorsProvider import com.fastaccess.provider.emoji.EmojiParser import com.fastaccess.ui.widgets.FontTextView -import com.fastaccess.ui.widgets.bindView import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder @@ -18,12 +18,13 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder open class TrendingViewHolder(itemView: View, adapter: BaseRecyclerAdapter>) : BaseViewHolder(itemView, adapter) { - val title: FontTextView by bindView(R.id.title) - val description: FontTextView by bindView(R.id.description) - val todayStars: FontTextView by bindView(R.id.todayStars) - val stars: FontTextView by bindView(R.id.stars) - val fork: FontTextView by bindView(R.id.forks) - val lang: FontTextView by bindView(R.id.language) + @BindView(R.id.title) lateinit var title: FontTextView + @BindView(R.id.description) lateinit var description: FontTextView + @BindView(R.id.todayStars) lateinit var todayStars: FontTextView + @BindView(R.id.stars) lateinit var stars: FontTextView + @BindView(R.id.forks) lateinit var fork: FontTextView + @BindView(R.id.language) lateinit var lang: FontTextView + override fun bind(t: TrendingModel) { title.text = t.title diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt new file mode 100644 index 00000000..6fe1a3cf --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt @@ -0,0 +1,11 @@ +package com.fastaccess.ui.adapter.viewholder + +import android.view.View +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by kosh on 07/08/2017. + */ +class UnknownTypeViewHolder(private val view: View) : BaseViewHolder(view) { + override fun bind(t: Any) {} //DO NOTHING +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/base/BaseActivity.java b/app/src/main/java/com/fastaccess/ui/base/BaseActivity.java index a9cb1cda..cedaa628 100644 --- a/app/src/main/java/com/fastaccess/ui/base/BaseActivity.java +++ b/app/src/main/java/com/fastaccess/ui/base/BaseActivity.java @@ -22,6 +22,7 @@ import android.view.View; import android.view.ViewTreeObserver; import android.widget.Toast; +import com.bumptech.glide.Glide; import com.evernote.android.state.State; import com.evernote.android.state.StateSaver; import com.fastaccess.App; @@ -31,20 +32,23 @@ import com.fastaccess.helper.AppHelper; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; import com.fastaccess.helper.PrefGetter; +import com.fastaccess.helper.RxHelper; import com.fastaccess.helper.ViewHelper; +import com.fastaccess.provider.markdown.CachedComments; import com.fastaccess.provider.theme.ThemeEngine; import com.fastaccess.ui.base.mvp.BaseMvp; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; import com.fastaccess.ui.modules.changelog.ChangelogBottomSheetDialog; +import com.fastaccess.ui.modules.gists.gist.GistActivity; import com.fastaccess.ui.modules.login.chooser.LoginChooserActivity; import com.fastaccess.ui.modules.main.MainActivity; import com.fastaccess.ui.modules.main.orgs.OrgListDialogFragment; +import com.fastaccess.ui.modules.repos.code.commit.details.CommitPagerActivity; +import com.fastaccess.ui.modules.repos.issues.issue.details.IssuePagerActivity; +import com.fastaccess.ui.modules.repos.pull_requests.pull_request.details.PullRequestPagerActivity; import com.fastaccess.ui.modules.settings.SettingsActivity; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.dialog.ProgressDialogFragment; -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.AdView; -import com.google.android.gms.ads.MobileAds; import net.grandcentrix.thirtyinch.TiActivity; @@ -55,6 +59,7 @@ import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Optional; import es.dmoral.toasty.Toasty; +import io.reactivex.Observable; /** @@ -65,12 +70,11 @@ public abstract class BaseActivity { + glide.clearDiskCache(); + PrefGetter.setToken(null); + PrefGetter.setOtpCode(null); + PrefGetter.resetEnterprise(); + Login.logout(); + return true; + })).subscribe(aBoolean -> { + glide.clearMemory(); + Intent intent = new Intent(this, LoginChooserActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finishAffinity(); + })); } @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { @@ -263,27 +272,6 @@ public abstract class BaseActivity, val extraNav: NavigationView?, val accountsNav: NavigationView?) +class MainNavDrawer(val view: BaseActivity<*, *>, private val extraNav: NavigationView?, private val accountsNav: NavigationView?) : BaseViewHolder.OnItemClickListener { - var menusHolder: ViewGroup? = null - val togglePinned: View? = view.findViewById(R.id.togglePinned) - val pinnedList: DynamicRecyclerView? = view.findViewById(R.id.pinnedList) - val pinnedListAdapter = PinnedReposAdapter(true) - val userModel: Login? = Login.getUser() + private var menusHolder: ViewGroup? = null + private val togglePinned: View? = view.findViewById(R.id.togglePinned) + private val pinnedList: DynamicRecyclerView? = view.findViewById(R.id.pinnedList) + private val pinnedListAdapter = PinnedReposAdapter(true) + private val userModel: Login? = Login.getUser() init { menusHolder = view.findViewById(R.id.menusHolder) @@ -113,14 +114,13 @@ class MainNavDrawer(val view: BaseActivity<*, *>, val extraNav: NavigationView?, } val adapter = LoginAdapter(true) view.getPresenter().manageViewDisposable(Login.getAccounts() - .doFinally { - when (!adapter.isEmpty) { - true -> { - toggleAccountsLayout.visibility = View.VISIBLE - adapter.listener = this - recyclerView.adapter = adapter - } - else -> toggleAccountsLayout.visibility = View.GONE + .doOnComplete { + if (!adapter.isEmpty) { + toggleAccountsLayout.visibility = View.VISIBLE + adapter.listener = this + recyclerView.adapter = adapter + } else { + toggleAccountsLayout.visibility = View.GONE } } .subscribe({ adapter.addItem(it) }, ::print)) @@ -164,7 +164,7 @@ class MainNavDrawer(val view: BaseActivity<*, *>, val extraNav: NavigationView?, if (!view.isFinishing()) { when { item.itemId == R.id.navToRepo -> view.onNavToRepoClicked() - item.itemId == R.id.gists -> GistsListActivity.startActivity(view, false) + item.itemId == R.id.gists -> GistsListActivity.startActivity(view) item.itemId == R.id.pinnedMenu -> PinnedReposActivity.startActivity(view) item.itemId == R.id.mainView -> { val intent = Intent(view, MainActivity::class.java) @@ -190,7 +190,7 @@ class MainNavDrawer(val view: BaseActivity<*, *>, val extraNav: NavigationView?, override fun onItemClick(position: Int, v: View, item: Login) { view.getPresenter().manageViewDisposable(RxHelper.getObservable(Login.onMultipleLogin(item, item.isIsEnterprise, false)) .doOnSubscribe { view.showProgress(0) } - .doFinally { view.hideProgress() } + .doOnComplete { view.hideProgress() } .subscribe({ view.onRestartApp() }, ::println)) } } \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/base/mvp/BaseMvp.java b/app/src/main/java/com/fastaccess/ui/base/mvp/BaseMvp.java index 87c30680..124feb18 100644 --- a/app/src/main/java/com/fastaccess/ui/base/mvp/BaseMvp.java +++ b/app/src/main/java/com/fastaccess/ui/base/mvp/BaseMvp.java @@ -79,7 +79,7 @@ public interface BaseMvp { void setPreviousTotal(int previousTotal); - void onCallApi(int page, @Nullable P parameter); + boolean onCallApi(int page, @Nullable P parameter); } interface OnScrollTopListener { diff --git a/app/src/main/java/com/fastaccess/ui/modules/about/FastHubAboutActivity.java b/app/src/main/java/com/fastaccess/ui/modules/about/FastHubAboutActivity.java index 9b4f7fdf..1de10fde 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/about/FastHubAboutActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/about/FastHubAboutActivity.java @@ -146,7 +146,7 @@ public class FastHubAboutActivity extends MaterialAboutActivity { .addItem(new MaterialAboutActionItem.Builder() .text(R.string.join_slack) .icon(ContextCompat.getDrawable(context, R.drawable.ic_slack)) - .setOnClickAction(() -> ActivityHelper.startCustomTab(this, "http://rebrand.ly/fasthub")) + .setOnClickAction(() -> ActivityHelper.startCustomTab(this, "http://rebrand.ly/fasthub-slack")) .build()) .addItem(new MaterialAboutActionItem.Builder() .text(R.string.open_source_libs) diff --git a/app/src/main/java/com/fastaccess/ui/modules/code/CodeViewerActivity.java b/app/src/main/java/com/fastaccess/ui/modules/code/CodeViewerActivity.java index 54bb6477..c7b96073 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/code/CodeViewerActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/code/CodeViewerActivity.java @@ -8,6 +8,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuItem; +import android.webkit.MimeTypeMap; import com.annimon.stream.Objects; import com.evernote.android.state.State; @@ -90,6 +91,7 @@ public class CodeViewerActivity extends BaseActivity { } String title = Uri.parse(url).getLastPathSegment(); setTitle(title); + if (toolbar != null) toolbar.setSubtitle(MimeTypeMap.getFileExtensionFromUrl(url)); setTaskName(title); } diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorActivity.java b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorActivity.java deleted file mode 100644 index 12f44435..00000000 --- a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorActivity.java +++ /dev/null @@ -1,354 +0,0 @@ -package com.fastaccess.ui.modules.editor; - -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.design.widget.Snackbar; -import android.support.transition.TransitionManager; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.ListView; - -import com.evernote.android.state.State; -import com.fastaccess.R; -import com.fastaccess.data.dao.EditReviewCommentModel; -import com.fastaccess.data.dao.model.Comment; -import com.fastaccess.helper.ActivityHelper; -import com.fastaccess.helper.AnimHelper; -import com.fastaccess.helper.AppHelper; -import com.fastaccess.helper.BundleConstant; -import com.fastaccess.helper.Bundler; -import com.fastaccess.helper.InputHelper; -import com.fastaccess.helper.PrefGetter; -import com.fastaccess.helper.PrefHelper; -import com.fastaccess.helper.ViewHelper; -import com.fastaccess.provider.markdown.MarkDownProvider; -import com.fastaccess.ui.base.BaseActivity; -import com.fastaccess.ui.modules.editor.popup.EditorLinkImageDialogFragment; -import com.fastaccess.ui.widgets.FontEditText; -import com.fastaccess.ui.widgets.FontTextView; -import com.fastaccess.ui.widgets.ForegroundImageView; -import com.fastaccess.ui.widgets.dialog.MessageDialogView; - -import java.util.ArrayList; - -import butterknife.BindView; -import butterknife.OnClick; -import butterknife.OnItemClick; -import butterknife.OnTextChanged; - -import static android.view.View.GONE; - -/** - * Created by Kosh on 27 Nov 2016, 1:32 AM - */ - -public class EditorActivity extends BaseActivity implements EditorMvp.View { - - private String sentFromFastHub; - - private ArrayList participants; - private int inMentionMode = -1; - private CharSequence savedText = ""; - @BindView(R.id.replyQuote) LinearLayout replyQuote; - @BindView(R.id.replyQuoteText) FontTextView quote; - @BindView(R.id.view) ForegroundImageView viewCode; - @BindView(R.id.editText) FontEditText editText; - @BindView(R.id.editorIconsHolder) View editorIconsHolder; - @BindView(R.id.sentVia) CheckBox sentVia; - @BindView(R.id.list_divider) View listDivider; - @BindView(R.id.parentView) View parentView; - @BindView(R.id.autocomplete) ListView mention; - - @State @BundleConstant.ExtraTYpe String extraType; - @State String itemId; - @State String login; - @State int issueNumber; - @State long commentId = 0; - @State String sha; - @State EditReviewCommentModel reviewComment; - - @Override protected int layout() { - return R.layout.editor_layout; - } - - @Override protected boolean isTransparent() { - return false; - } - - @Override protected boolean canBack() { - return true; - } - - @Override protected boolean isSecured() { - return false; - } - - @NonNull @Override public EditorPresenter providePresenter() { - return new EditorPresenter(); - } - - @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.TEXT_CHANGED) void onEdited(CharSequence charSequence) { - if (editText.isEnabled()) { - savedText = charSequence; - mention(charSequence); - } - } - - @OnItemClick(R.id.autocomplete) void onMentionSelection(int position) { - try { - String complete = mention.getAdapter().getItem(position).toString() + " "; - int end = editText.getSelectionEnd(); - editText.getText().replace(inMentionMode, end, complete, 0, complete.length()); - inMentionMode = -1; - } catch (Exception ignored) {} - mention.setVisibility(GONE); - listDivider.setVisibility(GONE); - } - - @OnClick(R.id.replyQuoteText) void onToggleQuote() { - TransitionManager.beginDelayedTransition((ViewGroup) parentView); - if (quote.getMaxLines() == 3) { - quote.setMaxLines(Integer.MAX_VALUE); - } else { - quote.setMaxLines(3); - } - quote.setCompoundDrawablesWithIntrinsicBounds(0, 0, - quote.getMaxLines() == 3 ? R.drawable.ic_arrow_drop_down : R.drawable.ic_arrow_drop_up, 0); - } - - @OnClick(R.id.view) void onViewMarkDown() { - if (editText.isEnabled() && !InputHelper.isEmpty(editText)) { - editText.setEnabled(false); - sentVia.setEnabled(false); - MarkDownProvider.setMdText(editText, InputHelper.toString(editText)); - ViewHelper.hideKeyboard(editText); - AnimHelper.animateVisibility(editorIconsHolder, false); - } else { - editText.setText(savedText); - editText.setSelection(savedText.length()); - editText.setEnabled(true); - sentVia.setEnabled(true); - ViewHelper.showKeyboard(editText); - AnimHelper.animateVisibility(editorIconsHolder, true); - } - } - - @OnClick({R.id.headerOne, R.id.headerTwo, R.id.headerThree, R.id.bold, R.id.italic, - R.id.strikethrough, R.id.bullet, R.id.header, R.id.code, R.id.numbered, - R.id.quote, R.id.link, R.id.image, R.id.unCheckbox, R.id.checkbox}) void onActions(View v) { - if (!editText.isEnabled()) { - Snackbar.make(editText, R.string.error_highlighting_editor, Snackbar.LENGTH_SHORT).show(); - return; - } - if (v.getId() == R.id.link) { - EditorLinkImageDialogFragment.newInstance(true).show(getSupportFragmentManager(), "BannerDialogFragment"); - } else if (v.getId() == R.id.image) { - EditorLinkImageDialogFragment.newInstance(false).show(getSupportFragmentManager(), "BannerDialogFragment"); - } else { - getPresenter().onActionClicked(editText, v.getId()); - } - } - - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setToolbarIcon(R.drawable.ic_clear); - sentFromFastHub = "\n\n_" + getString(R.string.sent_from_fasthub, AppHelper.getDeviceName(), "", - "[" + getString(R.string.app_name) + "](https://play.google.com/store/apps/details?id=com.fastaccess.github)") + "_"; - sentVia.setVisibility(PrefGetter.isSentViaBoxEnabled() ? View.VISIBLE : GONE); - sentVia.setChecked(PrefGetter.isSentViaEnabled()); - sentVia.setOnCheckedChangeListener((buttonView, isChecked) -> { - PrefHelper.set("sent_via", isChecked); - }); - MarkDownProvider.setMdText(sentVia, sentFromFastHub); - if (savedInstanceState == null) { - onCreate(); - } - if (!PrefGetter.isEditorHintShowed()) {} - if (editText.getText().toString().contains(sentFromFastHub)) { - editText.setText(editText.getText().toString().replace(sentFromFastHub, "")); - sentVia.setChecked(true); - } - - editText.requestFocus(); - } - - @Override public void onSendResultAndFinish(@NonNull Comment commentModel, boolean isNew) { - hideProgress(); - Intent intent = new Intent(); - intent.putExtras(Bundler.start() - .put(BundleConstant.ITEM, commentModel) - .put(BundleConstant.EXTRA, isNew) - .end()); - setResult(RESULT_OK, intent); - finish(); - } - - @Override public void onSendMarkDownResult() { - Intent intent = new Intent(); - intent.putExtras(Bundler.start().put(BundleConstant.EXTRA, savedText).end()); - setResult(RESULT_OK, intent); - finish(); - } - - @Override public void onSendReviewResultAndFinish(EditReviewCommentModel comment, boolean isNew) { - hideProgress(); - Intent intent = new Intent(); - intent.putExtras(Bundler.start() - .put(BundleConstant.ITEM, comment) - .put(BundleConstant.EXTRA, isNew) - .end()); - setResult(RESULT_OK, intent); - finish(); - } - - @Override public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.done_menu, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.submit) { - if (PrefGetter.isSentViaEnabled()) { - String temp = savedText.toString(); - if (!temp.contains(sentFromFastHub)) { - savedText = savedText + sentFromFastHub; - } - } - getPresenter().onHandleSubmission(savedText, extraType, itemId, commentId, login, issueNumber, sha, reviewComment); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override public boolean onPrepareOptionsMenu(Menu menu) { - if (menu.findItem(R.id.submit) != null) { - menu.findItem(R.id.submit).setEnabled(true); - } - return super.onPrepareOptionsMenu(menu); - } - - @Override public void showProgress(@StringRes int resId) { - super.showProgress(resId); - supportInvalidateOptionsMenu(); - } - - @Override public void hideProgress() { - supportInvalidateOptionsMenu(); - super.hideProgress(); - } - - @Override public void onBackPressed() { - if (InputHelper.isEmpty(editText)) { - super.onBackPressed(); - } else { - ViewHelper.hideKeyboard(editText); - MessageDialogView.newInstance(getString(R.string.close), getString(R.string.unsaved_data_warning), - Bundler.start().put("primary_extra", getString(R.string.discard)).put("secondary_extra", getString(R.string.cancel)) - .put(BundleConstant.EXTRA, true).end()).show(getSupportFragmentManager(), MessageDialogView.TAG); - } - } - - @Override public void onMessageDialogActionClicked(boolean isOk, @Nullable Bundle bundle) { - super.onMessageDialogActionClicked(isOk, bundle); - if (isOk && bundle != null) { - finish(); - } - } - - @Override public void onAppendLink(@Nullable String title, @Nullable String link, boolean isLink) { - if (isLink) { - MarkDownProvider.addLink(editText, InputHelper.toString(title), InputHelper.toString(link)); - } else { - editText.setText(String.format("%s\n", editText.getText())); - MarkDownProvider.addPhoto(editText, InputHelper.toString(title), InputHelper.toString(link)); - } - } - - private void onCreate() { - Intent intent = getIntent(); - if (intent != null && intent.getExtras() != null) { - Bundle bundle = intent.getExtras(); - //noinspection WrongConstant - extraType = bundle.getString(BundleConstant.EXTRA_TYPE); - reviewComment = bundle.getParcelable(BundleConstant.REVIEW_EXTRA); - itemId = bundle.getString(BundleConstant.ID); - login = bundle.getString(BundleConstant.EXTRA_TWO); - if (extraType.equalsIgnoreCase(BundleConstant.ExtraTYpe.EDIT_COMMIT_COMMENT_EXTRA) || - extraType.equalsIgnoreCase(BundleConstant.ExtraTYpe.NEW_COMMIT_COMMENT_EXTRA)) { - sha = bundle.getString(BundleConstant.EXTRA_THREE); - } else { - issueNumber = bundle.getInt(BundleConstant.EXTRA_THREE); - } - commentId = bundle.getLong(BundleConstant.EXTRA_FOUR); - String textToUpdate = bundle.getString(BundleConstant.EXTRA); - if (!InputHelper.isEmpty(textToUpdate)) { - editText.setText(String.format("%s ", textToUpdate)); - editText.setSelection(InputHelper.toString(editText).length()); - } - if (bundle.getString("message", "").isEmpty()) - replyQuote.setVisibility(GONE); - else { - MarkDownProvider.setMdText(quote, bundle.getString("message", "")); - } - participants = bundle.getStringArrayList("participants"); - } - } - - private void updateMentionList(@NonNull String mentioning) { - if (participants != null) { - ArrayList mentions = new ArrayList<>(); - for (String participant : participants) - if (participant.toLowerCase().startsWith(mentioning.replace("@", "").toLowerCase())) - mentions.add(participant); - ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, - android.R.id.text1, mentions.subList(0, Math.min(mentions.size(), 3))); - mention.setAdapter(adapter); - Log.d(getLoggingTag(), mentions.toString()); - } - } - - private void mention(CharSequence charSequence) { - try { - char lastChar = 0; - if (charSequence.length() > 0) lastChar = charSequence.charAt(charSequence.length() - 1); - if (lastChar != 0) { - if (lastChar == '@') { - inMentionMode = editText.getSelectionEnd(); - mention.setVisibility(GONE); - listDivider.setVisibility(GONE); - return; - } else if (lastChar == ' ') - inMentionMode = -1; - else if (inMentionMode > -1) - updateMentionList(charSequence.toString().substring(inMentionMode, editText.getSelectionEnd())); - else { - String copy = editText.getText().toString().substring(0, editText.getSelectionEnd()); - String[] list = copy.split("\\s+"); - String last = list[list.length - 1]; - if (last.startsWith("@")) { - inMentionMode = copy.lastIndexOf("@") + 1; - updateMentionList(charSequence.toString().substring(inMentionMode, editText.getSelectionEnd())); - } - } - } else { - inMentionMode = -1; - } - if (inMentionMode > -1) - if (mention != null) { - mention.setVisibility(inMentionMode > 0 ? View.VISIBLE : GONE); - listDivider.setVisibility(mention.getVisibility()); - } - } catch (Exception ignored) {} - } - -} diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorActivity.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorActivity.kt new file mode 100644 index 00000000..dd300dc2 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorActivity.kt @@ -0,0 +1,234 @@ +package com.fastaccess.ui.modules.editor + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.support.annotation.StringRes +import android.support.transition.TransitionManager +import android.support.v4.app.FragmentManager +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.View.GONE +import android.view.ViewGroup +import android.widget.EditText +import android.widget.LinearLayout +import android.widget.ListView +import butterknife.BindView +import butterknife.OnClick +import com.evernote.android.state.State +import com.fastaccess.R +import com.fastaccess.data.dao.EditReviewCommentModel +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.helper.* +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.provider.markdown.CachedComments +import com.fastaccess.provider.markdown.MarkDownProvider +import com.fastaccess.ui.base.BaseActivity +import com.fastaccess.ui.widgets.FontTextView +import com.fastaccess.ui.widgets.markdown.MarkDownLayout +import com.fastaccess.ui.widgets.markdown.MarkdownEditText +import java.util.* + +/** + * Created by Kosh on 27 Nov 2016, 1:32 AM + */ + +class EditorActivity : BaseActivity(), EditorMvp.View { + + private var participants: ArrayList? = null + private val sentFromFastHub: String by lazy { + "\n\n_" + getString(R.string.sent_from_fasthub, AppHelper.getDeviceName(), "", + "[" + getString(R.string.app_name) + "](https://play.google.com/store/apps/details?id=com.fastaccess.github)") + "_" + } + + @BindView(R.id.replyQuote) lateinit var replyQuote: LinearLayout + @BindView(R.id.replyQuoteText) lateinit var quote: FontTextView + @BindView(R.id.markDownLayout) lateinit var markDownLayout: MarkDownLayout + @BindView(R.id.editText) lateinit var editText: MarkdownEditText + @BindView(R.id.list_divider) lateinit var listDivider: View + @BindView(R.id.parentView) lateinit var parentView: View + @BindView(R.id.autocomplete) lateinit var mention: ListView + + @State + @BundleConstant.ExtraType + var extraType: String? = null + @State + var itemId: String? = null + @State + var login: String? = null + @State + var issueNumber: Int = 0 + @State + var commentId: Long = 0 + @State + var sha: String? = null + @State + var reviewComment: EditReviewCommentModel? = null + + override fun layout(): Int = R.layout.editor_layout + + override fun isTransparent(): Boolean = false + + override fun canBack(): Boolean = true + + override fun isSecured(): Boolean = false + + override fun providePresenter(): EditorPresenter = EditorPresenter() + + @OnClick(R.id.replyQuoteText) internal fun onToggleQuote() { + TransitionManager.beginDelayedTransition((parentView as ViewGroup)) + if (quote.maxLines == 3) { + quote.maxLines = Integer.MAX_VALUE + } else { + quote.maxLines = 3 + } + quote.setCompoundDrawablesWithIntrinsicBounds(0, 0, + if (quote.maxLines == 3) R.drawable.ic_arrow_drop_down + else R.drawable.ic_arrow_drop_up, 0) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + markDownLayout.markdownListener = this + setToolbarIcon(R.drawable.ic_clear) + if (savedInstanceState == null) { + onCreate() + } + invalidateOptionsMenu() + editText.initListView(mention, listDivider, participants) + editText.requestFocus() + } + + override fun onSendResultAndFinish(commentModel: Comment, isNew: Boolean) { + hideProgress() + val intent = Intent() + intent.putExtras(Bundler.start() + .put(BundleConstant.ITEM, commentModel) + .put(BundleConstant.EXTRA, isNew) + .end()) + setResult(Activity.RESULT_OK, intent) + finish() + } + + override fun onSendMarkDownResult() { + val intent = Intent() + intent.putExtras(Bundler.start().put(BundleConstant.EXTRA, editText.savedText).end()) + setResult(Activity.RESULT_OK, intent) + finish() + } + + override fun onSendReviewResultAndFinish(comment: EditReviewCommentModel, isNew: Boolean) { + hideProgress() + val intent = Intent() + intent.putExtras(Bundler.start() + .put(BundleConstant.ITEM, comment) + .put(BundleConstant.EXTRA, isNew) + .end()) + setResult(Activity.RESULT_OK, intent) + finish() + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.done_menu, menu) + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == R.id.submit) { + if (PrefGetter.isSentViaEnabled()) { + val temp = editText.savedText.toString() + if (!temp.contains(sentFromFastHub)) { + editText.savedText = editText.savedText.toString() + sentFromFastHub + } + } + presenter.onHandleSubmission(editText.savedText, extraType, itemId, commentId, login, issueNumber, sha, reviewComment) + return true + } + return super.onOptionsItemSelected(item) + } + + override fun onPrepareOptionsMenu(menu: Menu): Boolean { + if (menu.findItem(R.id.submit) != null) { + menu.findItem(R.id.submit).isEnabled = true + } + if (BundleConstant.ExtraType.FOR_RESULT_EXTRA.equals(extraType, ignoreCase = true)) { + menu.findItem(R.id.submit).setIcon(R.drawable.ic_done) + } + return super.onPrepareOptionsMenu(menu) + } + + override fun showProgress(@StringRes resId: Int) { + super.showProgress(resId) + invalidateOptionsMenu() + } + + override fun hideProgress() { + invalidateOptionsMenu() + super.hideProgress() + } + + override fun onBackPressed() { + if (!InputHelper.isEmpty(editText)) { + ViewHelper.hideKeyboard(editText) + } + super.onBackPressed() + } + + override fun onMessageDialogActionClicked(isOk: Boolean, bundle: Bundle?) { + super.onMessageDialogActionClicked(isOk, bundle) + if (isOk && bundle != null) { + finish() + } + } + + override fun onAppendLink(title: String?, link: String?, isLink: Boolean) { + if (isLink) { + MarkDownProvider.addLink(editText, InputHelper.toString(title), InputHelper.toString(link)) + } else { + editText.setText(String.format("%s\n", editText.text)) + MarkDownProvider.addPhoto(editText, InputHelper.toString(title), InputHelper.toString(link)) + } + } + + override fun getEditText(): EditText = editText + + override fun getSavedText(): CharSequence? = editText.savedText + + override fun fragmentManager(): FragmentManager = supportFragmentManager + + @SuppressLint("SetTextI18n") + override fun onEmojiAdded(emoji: Emoji?) { + markDownLayout.onEmojiAdded(emoji) + } + + private fun onCreate() { + val intent = intent + if (intent != null && intent.extras != null) { + val bundle = intent.extras + extraType = bundle.getString(BundleConstant.EXTRA_TYPE) + reviewComment = bundle.getParcelable(BundleConstant.REVIEW_EXTRA) + itemId = bundle.getString(BundleConstant.ID) + login = bundle.getString(BundleConstant.EXTRA_TWO) + if (extraType.equals(BundleConstant.ExtraType.EDIT_COMMIT_COMMENT_EXTRA, ignoreCase = true) + || extraType.equals(BundleConstant.ExtraType.NEW_COMMIT_COMMENT_EXTRA, ignoreCase = true)) { + sha = bundle.getString(BundleConstant.EXTRA_THREE) + } else { + issueNumber = bundle.getInt(BundleConstant.EXTRA_THREE) + } + commentId = bundle.getLong(BundleConstant.EXTRA_FOUR) + val textToUpdate = bundle.getString(BundleConstant.EXTRA) + if (!InputHelper.isEmpty(textToUpdate)) { + editText.setText(String.format("%s ", textToUpdate)) + editText.setSelection(InputHelper.toString(editText).length) + } + if (bundle.getString("message", "").isEmpty()) + replyQuote.visibility = GONE + else { + MarkDownProvider.setMdText(quote, bundle.getString("message", "")) + } + participants = bundle.getStringArrayList("participants") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorMvp.java b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorMvp.java deleted file mode 100644 index 83f4920a..00000000 --- a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorMvp.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.fastaccess.ui.modules.editor; - -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.widget.EditText; - -import com.fastaccess.data.dao.EditReviewCommentModel; -import com.fastaccess.data.dao.model.Comment; -import com.fastaccess.helper.BundleConstant; -import com.fastaccess.ui.base.mvp.BaseMvp; -import com.fastaccess.ui.modules.editor.popup.EditorLinkImageMvp; - -/** - * Created by Kosh on 27 Nov 2016, 1:31 AM - */ - -interface EditorMvp { - - interface View extends BaseMvp.FAView, EditorLinkImageMvp.EditorLinkCallback { - void onSendResultAndFinish(@NonNull Comment commentModel, boolean isNew); - - void onSendMarkDownResult(); - - void onSendReviewResultAndFinish(EditReviewCommentModel comment, boolean isNew); - } - - interface Presenter extends BaseMvp.FAPresenter { - - void onActionClicked(@NonNull EditText editText, @IdRes int id); - - void onEditGistComment(long id, @Nullable CharSequence savedText, @NonNull String gistId); - - void onSubmitGistComment(@Nullable CharSequence savedText, @NonNull String gistId); - - void onSubmitIssueComment(CharSequence savedText, @NonNull String itemId, @NonNull String login, int issueNumber); - - void onEditIssueComment(CharSequence savedText, @NonNull String itemId, long id, @NonNull String login, int issueNumber); - - void onSubmitCommitComment(CharSequence savedText, @NonNull String itemId, @NonNull String login, @NonNull String sha); - - void onEditCommitComment(CharSequence savedText, @NonNull String itemId, @NonNull String login, long id); - - void onHandleSubmission(@Nullable CharSequence savedText, @Nullable @BundleConstant.ExtraTYpe String extraType, - @Nullable String itemId, long id, @Nullable String login, int issueNumber, @Nullable String sha, - EditReviewCommentModel reviewComment); - } -} diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorMvp.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorMvp.kt new file mode 100644 index 00000000..11417617 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorMvp.kt @@ -0,0 +1,44 @@ +package com.fastaccess.ui.modules.editor + +import com.fastaccess.data.dao.EditReviewCommentModel +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.helper.BundleConstant +import com.fastaccess.ui.base.mvp.BaseMvp +import com.fastaccess.ui.modules.editor.emoji.EmojiMvp +import com.fastaccess.ui.modules.editor.popup.EditorLinkImageMvp +import com.fastaccess.ui.widgets.markdown.MarkDownLayout + +/** + * Created by Kosh on 27 Nov 2016, 1:31 AM + */ + +interface EditorMvp { + + interface View : BaseMvp.FAView, EditorLinkImageMvp.EditorLinkCallback, + MarkDownLayout.MarkdownListener, EmojiMvp.EmojiCallback { + fun onSendResultAndFinish(commentModel: Comment, isNew: Boolean) + + fun onSendMarkDownResult() + + fun onSendReviewResultAndFinish(comment: EditReviewCommentModel, isNew: Boolean) + } + + interface Presenter : BaseMvp.FAPresenter { + + fun onEditGistComment(id: Long, savedText: CharSequence?, gistId: String) + + fun onSubmitGistComment(savedText: CharSequence?, gistId: String) + + fun onSubmitIssueComment(savedText: CharSequence, itemId: String, login: String, issueNumber: Int) + + fun onEditIssueComment(savedText: CharSequence, itemId: String, id: Long, login: String, issueNumber: Int) + + fun onSubmitCommitComment(savedText: CharSequence, itemId: String, login: String, sha: String) + + fun onEditCommitComment(savedText: CharSequence, itemId: String, login: String, id: Long) + + fun onHandleSubmission(savedText: CharSequence?, @BundleConstant.ExtraType extraType: String?, + itemId: String?, id: Long, login: String?, issueNumber: Int, sha: String?, + reviewComment: EditReviewCommentModel?) + } +} diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorPresenter.java deleted file mode 100644 index cbc0cbfa..00000000 --- a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorPresenter.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.fastaccess.ui.modules.editor; - -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.widget.EditText; - -import com.fastaccess.R; -import com.fastaccess.data.dao.CommentRequestModel; -import com.fastaccess.data.dao.EditReviewCommentModel; -import com.fastaccess.helper.BundleConstant; -import com.fastaccess.helper.InputHelper; -import com.fastaccess.provider.markdown.MarkDownProvider; -import com.fastaccess.provider.rest.RestProvider; -import com.fastaccess.ui.base.mvp.presenter.BasePresenter; - -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.EDIT_COMMIT_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.EDIT_GIST_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.EDIT_ISSUE_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.EDIT_REVIEW_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.FOR_RESULT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.NEW_COMMIT_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.NEW_GIST_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.NEW_ISSUE_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.NEW_REVIEW_COMMENT_EXTRA; - -/** - * Created by Kosh on 27 Nov 2016, 1:31 AM - */ - -class EditorPresenter extends BasePresenter implements EditorMvp.Presenter { - - @Override public void onActionClicked(@NonNull EditText editText, @IdRes int id) { - if (editText.getSelectionEnd() == -1 || editText.getSelectionStart() == -1) { - return; - } - switch (id) { - case R.id.headerOne: - MarkDownProvider.addHeader(editText, 1); - break; - case R.id.headerTwo: - MarkDownProvider.addHeader(editText, 2); - break; - case R.id.headerThree: - MarkDownProvider.addHeader(editText, 3); - break; - case R.id.bold: - MarkDownProvider.addBold(editText); - break; - case R.id.italic: - MarkDownProvider.addItalic(editText); - break; - case R.id.strikethrough: - MarkDownProvider.addStrikeThrough(editText); - break; - case R.id.numbered: - MarkDownProvider.addList(editText, "1."); - break; - case R.id.bullet: - MarkDownProvider.addList(editText, "-"); - break; - case R.id.header: - MarkDownProvider.addDivider(editText); - break; - case R.id.code: - MarkDownProvider.addCode(editText); - break; - case R.id.quote: - MarkDownProvider.addQuote(editText); - break; - case R.id.link: - MarkDownProvider.addLink(editText); - break; - case R.id.image: - MarkDownProvider.addPhoto(editText); - break; - case R.id.checkbox: - MarkDownProvider.addList(editText, "- [x]"); - break; - case R.id.unCheckbox: - MarkDownProvider.addList(editText, "- [ ]"); - break; - } - } - - @Override public void onEditGistComment(long id, @Nullable CharSequence savedText, @NonNull String gistId) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - makeRestCall(RestProvider.getGistService(isEnterprise()).editGistComment(gistId, id, requestModel), - comment -> sendToView(view -> view.onSendResultAndFinish(comment, false)), false); - } - } - - @Override public void onSubmitGistComment(@Nullable CharSequence savedText, @NonNull String gistId) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - makeRestCall(RestProvider.getGistService(isEnterprise()).createGistComment(gistId, requestModel), - comment -> sendToView(view -> view.onSendResultAndFinish(comment, true)), false); - } - } - - @Override public void onHandleSubmission(@Nullable CharSequence savedText, @Nullable @BundleConstant.ExtraTYpe String extraType, - @Nullable String itemId, long id, @Nullable String login, int issueNumber, - @Nullable String sha, EditReviewCommentModel reviewComment) { - if (extraType == null) { - throw new NullPointerException("extraType is null"); - } - switch (extraType) { - case EDIT_GIST_COMMENT_EXTRA: - if (itemId == null) { - throw new NullPointerException("itemId is null"); - } - onEditGistComment(id, savedText, itemId); - break; - case NEW_GIST_COMMENT_EXTRA: - if (itemId == null) { - throw new NullPointerException("itemId is null"); - } - onSubmitGistComment(savedText, itemId); - break; - case FOR_RESULT_EXTRA: - sendToView(EditorMvp.View::onSendMarkDownResult); - break; - case EDIT_ISSUE_COMMENT_EXTRA: - if (itemId == null || login == null) { - throw new NullPointerException("itemId or login is null"); - } - onEditIssueComment(savedText, itemId, id, login, issueNumber); - break; - case NEW_ISSUE_COMMENT_EXTRA: - if (itemId == null || login == null) { - throw new NullPointerException("itemId or login is null"); - } - onSubmitIssueComment(savedText, itemId, login, issueNumber); - break; - case NEW_COMMIT_COMMENT_EXTRA: - if (itemId == null || login == null || sha == null) { - throw new NullPointerException("itemId or login is null"); - } - onSubmitCommitComment(savedText, itemId, login, sha); - break; - case EDIT_COMMIT_COMMENT_EXTRA: - if (itemId == null || login == null) { - throw new NullPointerException("itemId or login is null"); - } - onEditCommitComment(savedText, itemId, login, id); - break; - case NEW_REVIEW_COMMENT_EXTRA: - if (reviewComment == null || itemId == null || login == null || savedText == null) { - throw new NullPointerException("reviewComment null"); - } - onSubmitReviewComment(reviewComment, savedText, itemId, login, issueNumber); - break; - case EDIT_REVIEW_COMMENT_EXTRA: - if (reviewComment == null || itemId == null || login == null || savedText == null) { - throw new NullPointerException("reviewComment null"); - } - onEditReviewComment(reviewComment, savedText, itemId, login, issueNumber, id); - break; - } - } - - private void onEditReviewComment(@NonNull EditReviewCommentModel reviewComment, @NonNull CharSequence savedText, @NonNull String repoId, - @NonNull String login, int issueNumber, long id) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); -// requestModel.setInReplyTo(reviewComment.getInReplyTo()); - makeRestCall(RestProvider.getReviewService(isEnterprise()).editComment(login, repoId, id, requestModel) - .map(comment -> { - reviewComment.setCommentModel(comment); - return reviewComment; - }), comment -> sendToView(view -> view.onSendReviewResultAndFinish(comment, false)), false); - } - } - - private void onSubmitReviewComment(@NonNull EditReviewCommentModel reviewComment, @NonNull CharSequence savedText, - @NonNull String repoId, @NonNull String login, int issueNumber) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - requestModel.setInReplyTo(reviewComment.getInReplyTo()); - makeRestCall(RestProvider.getReviewService(isEnterprise()).submitComment(login, repoId, issueNumber, requestModel) - .map(comment -> { - reviewComment.setCommentModel(comment); - return reviewComment; - }), comment -> sendToView(view -> view.onSendReviewResultAndFinish(comment, true)), false); - } - } - - @Override public void onSubmitIssueComment(CharSequence savedText, @NonNull String itemId, @NonNull String login, int issueNumber) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - makeRestCall(RestProvider.getIssueService(isEnterprise()).createIssueComment(login, itemId, issueNumber, requestModel), - comment -> sendToView(view -> view.onSendResultAndFinish(comment, true))); - } - } - - @Override public void onEditIssueComment(CharSequence savedText, @NonNull String itemId, long id, @NonNull String login, int issueNumber) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - makeRestCall(RestProvider.getIssueService(isEnterprise()).editIssueComment(login, itemId, id, requestModel), - comment -> sendToView(view -> view.onSendResultAndFinish(comment, false)), false); - } - } - - @Override public void onSubmitCommitComment(CharSequence savedText, @NonNull String itemId, @NonNull String login, @NonNull String sha) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - makeRestCall(RestProvider.getRepoService(isEnterprise()).postCommitComment(login, itemId, sha, requestModel), - comment -> sendToView(view -> view.onSendResultAndFinish(comment, true)), false); - } - } - - @Override public void onEditCommitComment(CharSequence savedText, @NonNull String itemId, @NonNull String login, long id) { - if (!InputHelper.isEmpty(savedText)) { - CommentRequestModel requestModel = new CommentRequestModel(); - requestModel.setBody(savedText.toString()); - makeRestCall(RestProvider.getRepoService(isEnterprise()).editCommitComment(login, itemId, id, requestModel), - comment -> sendToView(view -> view.onSendResultAndFinish(comment, false)), false); - } - } -} diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/EditorPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorPresenter.kt new file mode 100644 index 00000000..149dd7e2 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/EditorPresenter.kt @@ -0,0 +1,157 @@ +package com.fastaccess.ui.modules.editor + +import com.fastaccess.data.dao.CommentRequestModel +import com.fastaccess.data.dao.EditReviewCommentModel +import com.fastaccess.data.dao.model.Comment +import com.fastaccess.helper.BundleConstant +import com.fastaccess.helper.BundleConstant.ExtraType.* +import com.fastaccess.helper.InputHelper +import com.fastaccess.provider.rest.RestProvider +import com.fastaccess.ui.base.mvp.presenter.BasePresenter + +/** + * Created by Kosh on 27 Nov 2016, 1:31 AM + */ + +class EditorPresenter : BasePresenter(), EditorMvp.Presenter { + + override fun onEditGistComment(id: Long, savedText: CharSequence?, gistId: String) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText!!.toString() + makeRestCall(RestProvider.getGistService(isEnterprise).editGistComment(gistId, id, requestModel), + { comment -> sendToView { view -> view.onSendResultAndFinish(comment, false) } }, false) + } + } + + override fun onSubmitGistComment(savedText: CharSequence?, gistId: String) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText!!.toString() + makeRestCall(RestProvider.getGistService(isEnterprise).createGistComment(gistId, requestModel), + { comment -> sendToView { view -> view.onSendResultAndFinish(comment, true) } }, false) + } + } + + override fun onHandleSubmission(savedText: CharSequence?, @BundleConstant.ExtraType extraType: String?, + itemId: String?, id: Long, login: String?, issueNumber: Int, + sha: String?, reviewComment: EditReviewCommentModel?) { + if (extraType == null) { + throw NullPointerException("extraType is null") + } + when (extraType) { + EDIT_GIST_COMMENT_EXTRA -> { + if (itemId == null) { + throw NullPointerException("itemId is null") + } + onEditGistComment(id, savedText, itemId) + } + NEW_GIST_COMMENT_EXTRA -> { + if (itemId == null) { + throw NullPointerException("itemId is null") + } + onSubmitGistComment(savedText, itemId) + } + FOR_RESULT_EXTRA -> sendToView({ it.onSendMarkDownResult() }) + EDIT_ISSUE_COMMENT_EXTRA -> { + if (itemId == null || login == null) { + throw NullPointerException("itemId or login is null") + } + onEditIssueComment(savedText!!, itemId, id, login, issueNumber) + } + NEW_ISSUE_COMMENT_EXTRA -> { + if (itemId == null || login == null) { + throw NullPointerException("itemId or login is null") + } + onSubmitIssueComment(savedText!!, itemId, login, issueNumber) + } + NEW_COMMIT_COMMENT_EXTRA -> { + if (itemId == null || login == null || sha == null) { + throw NullPointerException("itemId or login is null") + } + onSubmitCommitComment(savedText!!, itemId, login, sha) + } + EDIT_COMMIT_COMMENT_EXTRA -> { + if (itemId == null || login == null) { + throw NullPointerException("itemId or login is null") + } + onEditCommitComment(savedText!!, itemId, login, id) + } + NEW_REVIEW_COMMENT_EXTRA -> { + if (reviewComment == null || itemId == null || login == null || savedText == null) { + throw NullPointerException("reviewComment null") + } + onSubmitReviewComment(reviewComment, savedText, itemId, login, issueNumber) + } + EDIT_REVIEW_COMMENT_EXTRA -> { + if (reviewComment == null || itemId == null || login == null || savedText == null) { + throw NullPointerException("reviewComment null") + } + onEditReviewComment(reviewComment, savedText, itemId, login, issueNumber, id) + } + } + } + + private fun onEditReviewComment(reviewComment: EditReviewCommentModel, savedText: CharSequence, repoId: String, + login: String, issueNumber: Int, id: Long) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText.toString() + makeRestCall(RestProvider.getReviewService(isEnterprise).editComment(login, repoId, id, requestModel) + .map { comment -> + reviewComment.commentModel = comment + reviewComment + }, { comment -> sendToView { view -> view.onSendReviewResultAndFinish(comment, false) } }, false) + } + } + + private fun onSubmitReviewComment(reviewComment: EditReviewCommentModel, savedText: CharSequence, + repoId: String, login: String, issueNumber: Int) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText.toString() + requestModel.inReplyTo = reviewComment.inReplyTo + makeRestCall(RestProvider.getReviewService(isEnterprise).submitComment(login, repoId, issueNumber.toLong(), requestModel) + .map { comment -> + reviewComment.commentModel = comment + reviewComment + }, { comment -> sendToView { view -> view.onSendReviewResultAndFinish(comment, true) } }, false) + } + } + + override fun onSubmitIssueComment(savedText: CharSequence, itemId: String, login: String, issueNumber: Int) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText.toString() + makeRestCall(RestProvider.getIssueService(isEnterprise).createIssueComment(login, itemId, issueNumber, requestModel) + ) { comment -> sendToView { view -> view.onSendResultAndFinish(comment, true) } } + } + } + + override fun onEditIssueComment(savedText: CharSequence, itemId: String, id: Long, login: String, issueNumber: Int) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText.toString() + makeRestCall(RestProvider.getIssueService(isEnterprise).editIssueComment(login, itemId, id, requestModel), + { comment -> sendToView { view -> view.onSendResultAndFinish(comment, false) } }, false) + } + } + + override fun onSubmitCommitComment(savedText: CharSequence, itemId: String, login: String, sha: String) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText.toString() + makeRestCall(RestProvider.getRepoService(isEnterprise).postCommitComment(login, itemId, sha, requestModel), + { comment -> sendToView { view -> view.onSendResultAndFinish(comment, true) } }, false) + } + } + + override fun onEditCommitComment(savedText: CharSequence, itemId: String, login: String, id: Long) { + if (!InputHelper.isEmpty(savedText)) { + val requestModel = CommentRequestModel() + requestModel.body = savedText.toString() + makeRestCall(RestProvider.getRepoService(isEnterprise).editCommitComment(login, itemId, id, requestModel), + { comment -> sendToView { view -> view.onSendResultAndFinish(comment, false) } }, false) + } + } +} diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/comment/CommentEditorFragment.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/comment/CommentEditorFragment.kt new file mode 100644 index 00000000..5d794f69 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/comment/CommentEditorFragment.kt @@ -0,0 +1,142 @@ +package com.fastaccess.ui.modules.editor.comment + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.support.transition.TransitionManager +import android.support.v4.app.FragmentManager +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import butterknife.BindView +import butterknife.OnClick +import com.fastaccess.R +import com.fastaccess.helper.BundleConstant +import com.fastaccess.helper.Bundler +import com.fastaccess.helper.InputHelper +import com.fastaccess.helper.ViewHelper +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.ui.base.BaseFragment +import com.fastaccess.ui.base.mvp.BaseMvp +import com.fastaccess.ui.base.mvp.presenter.BasePresenter +import com.fastaccess.ui.modules.editor.EditorActivity +import com.fastaccess.ui.modules.editor.emoji.EmojiMvp +import com.fastaccess.ui.widgets.markdown.MarkDownLayout +import com.fastaccess.ui.widgets.markdown.MarkdownEditText + +/** + * Created by kosh on 21/08/2017. + */ +class CommentEditorFragment : BaseFragment>(), MarkDownLayout.MarkdownListener, + EmojiMvp.EmojiCallback { + + @BindView(R.id.commentBox) lateinit var commentBox: View + @BindView(R.id.markdDownLayout) lateinit var markdDownLayout: MarkDownLayout + @BindView(R.id.commentText) lateinit var commentText: MarkdownEditText + @BindView(R.id.markdownBtnHolder) lateinit var markdownBtnHolder: View + private var commentListener: CommentListener? = null + + @OnClick(R.id.sendComment) internal fun onComment() { + if (!InputHelper.isEmpty(getEditText())) { + commentListener?.onSendActionClicked(InputHelper.toString(getEditText()), arguments?.getBundle(BundleConstant.ITEM)) + getEditText().setText("") + ViewHelper.hideKeyboard(getEditText()) + arguments = null + } + } + + @OnClick(R.id.fullScreenComment) internal fun onExpandScreen() { + val intent = Intent(context, EditorActivity::class.java) + intent.putExtras(Bundler.start() + .put(BundleConstant.EXTRA_TYPE, BundleConstant.ExtraType.FOR_RESULT_EXTRA) + .put(BundleConstant.EXTRA, getEditText().text.toString()) + .end()) + startActivityForResult(intent, BundleConstant.REQUEST_CODE) + } + + @OnClick(R.id.toggleButtons) internal fun onToggleButtons(v: View) { + TransitionManager.beginDelayedTransition((view as ViewGroup?)!!) + v.isActivated = !v.isActivated + markdownBtnHolder.visibility = if (markdownBtnHolder.visibility == View.VISIBLE) View.GONE else View.VISIBLE + } + + override fun onAttach(context: Context?) { + super.onAttach(context) + if (parentFragment is CommentListener) { + commentListener = parentFragment as CommentListener + } else if (context is CommentListener) { + commentListener = context + } + } + + override fun onDetach() { + commentListener = null + super.onDetach() + } + + override fun providePresenter(): BasePresenter = BasePresenter() + + override fun fragmentLayout(): Int = R.layout.comment_box_layout + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + markdDownLayout.markdownListener = this + if (savedInstanceState == null) { + commentText.setText(arguments?.getBundle(BundleConstant.ITEM)?.getString(BundleConstant.EXTRA)) + } + } + + override fun getEditText(): EditText = commentText + + override fun fragmentManager(): FragmentManager = childFragmentManager + + override fun getSavedText(): CharSequence? = commentText.savedText + + override fun onEmojiAdded(emoji: Emoji?) = markdDownLayout.onEmojiAdded(emoji) + + @SuppressLint("SetTextI18n") + fun onCreateComment(text: String, bundle: Bundle?) { + arguments = Bundler.start().put(BundleConstant.ITEM, bundle).end() + commentText.setText("${if (commentText.text.isNullOrBlank()) "" else "${commentText.text} "}$text") + getEditText().setSelection(getEditText().text.length) + commentText.requestFocus() + ViewHelper.showKeyboard(commentText) + } + + fun onAddUserName(username: String) { + getEditText().setText(if (getEditText().text.isNullOrBlank()) { + "@$username" + } else { + "${getEditText().text} @$username" + }) + getEditText().setSelection(getEditText().text.length) + } + + interface CommentListener { + fun onCreateComment(text: String, bundle: Bundle?) {} + fun onSendActionClicked(text: String, bundle: Bundle?) + fun onTagUser(username: String) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + if (requestCode == BundleConstant.REQUEST_CODE) { + val text = data?.extras?.getCharSequence(BundleConstant.EXTRA) + getEditText().setText(text) + getEditText().setSelection(getEditText().text.length) + } + } + } + + companion object { + fun newInstance(bundle: Bundle?): CommentEditorFragment { + val fragment = CommentEditorFragment() + bundle?.let { + fragment.arguments = Bundler.start().put(BundleConstant.ITEM, bundle).end() + } + return fragment + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt new file mode 100644 index 00000000..3e46961f --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt @@ -0,0 +1,76 @@ +package com.fastaccess.ui.modules.editor.emoji + +import android.content.Context +import android.os.Bundle +import android.text.Editable +import android.view.View +import butterknife.BindView +import butterknife.OnTextChanged +import com.fastaccess.R +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.ui.adapter.EmojiAdapter +import com.fastaccess.ui.base.BaseMvpBottomSheetDialogFragment +import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView +import com.fastaccess.ui.widgets.recyclerview.layout_manager.GridManager +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller + +/** + * Created by kosh on 17/08/2017. + */ +class EmojiBottomSheet : BaseMvpBottomSheetDialogFragment(), EmojiMvp.View { + + @BindView(R.id.recycler) lateinit var recycler: DynamicRecyclerView + @BindView(R.id.fastScroller) lateinit var fastScroller: RecyclerViewFastScroller + + val adapter: EmojiAdapter by lazy { EmojiAdapter(this) } + + var emojiCallback: EmojiMvp.EmojiCallback? = null + + + @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) + fun onTextChange(text: Editable) { + adapter.filter.filter(text) + } + + override fun onAttach(context: Context) { + super.onAttach(context) + when { + parentFragment is EmojiMvp.EmojiCallback -> emojiCallback = parentFragment as EmojiMvp.EmojiCallback + context is EmojiMvp.EmojiCallback -> emojiCallback = context + else -> throw IllegalArgumentException("${context.javaClass.simpleName} must implement EmojiMvp.EmojiCallback") + } + } + + override fun onDetach() { + emojiCallback = null + super.onDetach() + } + + override fun fragmentLayout(): Int = R.layout.emoji_popup_layout + + override fun providePresenter(): EmojiPresenter = EmojiPresenter() + + override fun clearAdapter() { + adapter.clear() + } + + override fun onAddEmoji(emoji: Emoji) { + adapter.addItem(emoji) + } + + override fun onItemClick(position: Int, v: View?, item: Emoji) { + emojiCallback?.onEmojiAdded(item) + dismiss() + } + + override fun onItemLongClick(position: Int, v: View?, item: Emoji?) {} + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + recycler.adapter = adapter + fastScroller.attachRecyclerView(recycler) + presenter.onLoadEmoji() + val gridManager = recycler.layoutManager as GridManager + gridManager.iconSize = resources.getDimensionPixelSize(R.dimen.header_icon_zie) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiMvp.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiMvp.kt new file mode 100644 index 00000000..eec2eb1f --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiMvp.kt @@ -0,0 +1,24 @@ +package com.fastaccess.ui.modules.editor.emoji + +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.ui.base.mvp.BaseMvp +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder + +/** + * Created by kosh on 17/08/2017. + */ +interface EmojiMvp { + + interface View : BaseMvp.FAView, BaseViewHolder.OnItemClickListener { + fun clearAdapter() + fun onAddEmoji(emoji: Emoji) + } + + interface Presenter { + fun onLoadEmoji() + } + + interface EmojiCallback { + fun onEmojiAdded(emoji: Emoji?) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiPresenter.kt new file mode 100644 index 00000000..3ae507b8 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiPresenter.kt @@ -0,0 +1,29 @@ +package com.fastaccess.ui.modules.editor.emoji + +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.provider.emoji.EmojiManager +import com.fastaccess.ui.base.mvp.presenter.BasePresenter +import io.reactivex.Observable + +/** + * Created by kosh on 17/08/2017. + */ + +class EmojiPresenter : BasePresenter(), EmojiMvp.Presenter { + override fun onLoadEmoji() { + manageObservable(Observable.create { e -> + val emojies = EmojiManager.getAll() + emojies?.let { + it.onEach { + if (!e.isDisposed) { + e.onNext(it) + } + } + } + e.onComplete() + } + .doOnSubscribe { sendToView { it.clearAdapter() } } + .doOnNext { emoji -> sendToView { it.onAddEmoji(emoji) } }) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsFragment.java index eecd79d0..ea253bc6 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsFragment.java @@ -27,6 +27,7 @@ import com.fastaccess.ui.modules.repos.code.commit.details.CommitPagerActivity; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.ListDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.ArrayList; import java.util.List; @@ -45,6 +46,7 @@ public class FeedsFragment extends BaseFragment i @BindView(R.id.recycler) DynamicRecyclerView recycler; @BindView(R.id.refresh) SwipeRefreshLayout refresh; @BindView(R.id.stateLayout) StateLayout stateLayout; + @BindView(R.id.fastScroller) RecyclerViewFastScroller fastScroller; private FeedsAdapter adapter; private OnLoadMore onLoadMore; @@ -79,6 +81,7 @@ public class FeedsFragment extends BaseFragment i recycler.addDivider(); } recycler.addOnScrollListener(getLoadMore()); + fastScroller.attachRecyclerView(recycler); if (getPresenter().getEvents().isEmpty() && !getPresenter().isApiCalled()) { getPresenter().onFragmentCreated(getArguments()); } diff --git a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java index 107d493a..051c8775 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java +++ b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java @@ -40,7 +40,7 @@ public interface FeedsMvp { void onFragmentCreated(@NonNull Bundle argument); - void onCallApi(int page); + boolean onCallApi(int page); @NonNull ArrayList getEvents(); diff --git a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsPresenter.java index 8496c13f..6578a7f3 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsPresenter.java @@ -19,6 +19,7 @@ import com.fastaccess.data.dao.model.Repo; import com.fastaccess.data.dao.types.EventsType; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.Logger; import com.fastaccess.helper.PrefGetter; import com.fastaccess.helper.RxHelper; import com.fastaccess.provider.rest.RestProvider; @@ -53,22 +54,23 @@ public class FeedsPresenter extends BasePresenter implements Feed } } - @Override public void onCallApi(int page) { + @Override public boolean onCallApi(int page) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } if (page > lastPage || lastPage == 0) { sendToView(FeedsMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); Login login = Login.getUser(); - if (login == null) return;// I can't understand how this could possibly be reached lol. + if (login == null) return false;// I can't understand how this could possibly be reached lol. Observable> observable; + Logger.e(isOrg); if (user != null) { if (isOrg) { - observable = RestProvider.getOrgService(isEnterprise()).getReceivedEvents(user, page); + observable = RestProvider.getOrgService(isEnterprise()).getReceivedEvents(login.getLogin(), user, page); } else { observable = RestProvider.getUserService(login.getLogin().equalsIgnoreCase(user) ? PrefGetter.isEnterprise() : isEnterprise()).getUserEvents(user, page); @@ -83,6 +85,7 @@ public class FeedsPresenter extends BasePresenter implements Feed } sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @Override public int getCurrentPage() { @@ -101,8 +104,8 @@ public class FeedsPresenter extends BasePresenter implements Feed this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable Object parameter) { - onCallApi(page); + @Override public boolean onCallApi(int page, @Nullable Object parameter) { + return onCallApi(page); } @Override public void onSubscribed(boolean cancelable) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/filter/issues/FilterIssuesActivity.java b/app/src/main/java/com/fastaccess/ui/modules/filter/issues/FilterIssuesActivity.java index e4515912..93065843 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/filter/issues/FilterIssuesActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/filter/issues/FilterIssuesActivity.java @@ -9,10 +9,8 @@ import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.text.Editable; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; -import android.view.inputmethod.EditorInfo; import android.widget.PopupWindow; import android.widget.Toast; @@ -73,6 +71,7 @@ public class FilterIssuesActivity extends BaseActivity onLoadMore; private IssuesAdapter adapter; @@ -165,6 +167,7 @@ public class FilterIssueFragment extends BaseFragment im this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1 || parameter == null) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } if (page > lastPage || lastPage == 0 || parameter == null) { sendToView(FilterIssuesMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); makeRestCall(RestProvider.getSearchService(isEnterprise()).searchIssues(parameter, page), @@ -70,5 +70,6 @@ public class FilterIssuePresenter extends BasePresenter im } sendToView(view -> view.onNotifyAdapter(issues.getItems(), page)); }); + return true; } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsFragment.java index ecd26281..eb0de57f 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsFragment.java @@ -14,6 +14,7 @@ import com.fastaccess.ui.adapter.GistsAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,7 +31,7 @@ public class GistsFragment extends BaseFragment i @BindView(R.id.recycler) DynamicRecyclerView recycler; @BindView(R.id.refresh) SwipeRefreshLayout refresh; @BindView(R.id.stateLayout) StateLayout stateLayout; - + @BindView(R.id.fastScroller) RecyclerViewFastScroller fastScroller; private GistsAdapter adapter; private OnLoadMore onLoadMore; @@ -56,6 +57,7 @@ public class GistsFragment extends BaseFragment i if (getPresenter().getGists().isEmpty() && !getPresenter().isApiCalled()) { onRefresh(); } + fastScroller.attachRecyclerView(recycler); } @Override public void onRefresh() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java index 3a47d5d3..6d511c8b 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java @@ -8,12 +8,10 @@ import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; -import com.evernote.android.state.State; import com.fastaccess.R; import com.fastaccess.data.dao.FragmentPagerAdapterModel; import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; -import com.fastaccess.helper.Bundler; import com.fastaccess.ui.adapter.FragmentsPagerAdapter; import com.fastaccess.ui.base.BaseActivity; import com.fastaccess.ui.base.BaseFragment; @@ -34,17 +32,12 @@ public class GistsListActivity extends BaseActivity { @BindView(R.id.tabs) TabLayout tabs; @BindView(R.id.gistsContainer) ViewPagerView pager; - - public static void startActivity(@NonNull Context context, boolean myGists) { - Intent intent = new Intent(context, GistsListActivity.class); - intent.putExtras(Bundler.start().put(BundleConstant.EXTRA, myGists).end()); - context.startActivity(intent); - } - - @State boolean myGists; - @BindView(R.id.fab) FloatingActionButton fab; + public static void startActivity(@NonNull Context context) { + context.startActivity(new Intent(context, GistsListActivity.class)); + } + @Override protected int layout() { return R.layout.gists_activity_layout; } @@ -88,12 +81,20 @@ public class GistsListActivity extends BaseActivity { } @OnClick(R.id.fab) public void onViewClicked() { - ActivityHelper.startReveal(this, new Intent(this, CreateGistActivity.class), fab); + ActivityHelper.startReveal(this, new Intent(this, CreateGistActivity.class), fab, BundleConstant.REQUEST_CODE); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && requestCode == BundleConstant.REQUEST_CODE) { + if (pager != null && pager.getAdapter() != null) { + ((Fragment) pager.getAdapter().instantiateItem(pager, 0)).onActivityResult(resultCode, resultCode, data); + } + } } private void setupTabs() { - pager.setAdapter(new FragmentsPagerAdapter(getSupportFragmentManager(), - FragmentPagerAdapterModel.buildForGists(this))); + pager.setAdapter(new FragmentsPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapterModel.buildForGists(this))); tabs.setupWithViewPager(pager); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsPresenter.java index f07a0ee7..8e4e7f76 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsPresenter.java @@ -43,14 +43,14 @@ class GistsPresenter extends BasePresenter implements GistsMvp.Pr super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable Object parameter) { + @Override public boolean onCallApi(int page, @Nullable Object parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } if (page > lastPage || lastPage == 0) { sendToView(GistsMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); makeRestCall(RestProvider.getGistService(isEnterprise()).getPublicGists(RestProvider.PAGE_SIZE, page), @@ -58,6 +58,7 @@ class GistsPresenter extends BasePresenter implements GistsMvp.Pr lastPage = listResponse.getLast(); sendToView(view -> view.onNotifyAdapter(listResponse.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getGists() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistActivity.java b/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistActivity.java index 51d3aa1a..b975221b 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistActivity.java @@ -1,30 +1,35 @@ package com.fastaccess.ui.modules.gists.create; +import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.TextInputLayout; -import android.view.MotionEvent; +import android.support.v4.app.Fragment; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; -import android.widget.TextView; +import com.evernote.android.state.State; import com.fastaccess.R; +import com.fastaccess.data.dao.FilesListModel; import com.fastaccess.data.dao.model.Gist; -import com.fastaccess.helper.ActivityHelper; +import com.fastaccess.data.dao.model.Login; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.Logger; import com.fastaccess.helper.PrefGetter; import com.fastaccess.helper.ViewHelper; -import com.fastaccess.provider.markdown.MarkDownProvider; import com.fastaccess.ui.base.BaseActivity; -import com.fastaccess.ui.modules.editor.EditorActivity; +import com.fastaccess.ui.modules.gists.gist.files.GistFilesListFragment; import com.fastaccess.ui.widgets.dialog.MessageDialogView; +import java.util.ArrayList; + import butterknife.BindView; import butterknife.OnClick; -import butterknife.OnTouch; /** * Created by Kosh on 30 Nov 2016, 11:02 AM @@ -33,14 +38,43 @@ import butterknife.OnTouch; public class CreateGistActivity extends BaseActivity implements CreateGistMvp.View { @BindView(R.id.description) TextInputLayout description; - @BindView(R.id.fileName) TextInputLayout fileName; - @BindView(R.id.fileContent) TextView fileContent; - private CharSequence savedText; + @BindView(R.id.buttonsHolder) View buttonsHolder; + @State String id; - @Override public void onSetCode(@NonNull CharSequence charSequence) { - this.savedText = charSequence; - //noinspection ConstantConditions - MarkDownProvider.setMdText(fileContent, InputHelper.toString(charSequence)); + private GistFilesListFragment filesListFragment; + + + public static void start(@NonNull Activity context, @NonNull Gist gistsModel) { + Intent starter = new Intent(context, CreateGistActivity.class); + putBundle(gistsModel, starter); + context.startActivityForResult(starter, BundleConstant.REQUEST_CODE); + } + + public static void start(@NonNull Fragment context, @NonNull Gist gistsModel) { + Intent starter = new Intent(context.getContext(), CreateGistActivity.class); + putBundle(gistsModel, starter); + context.startActivityForResult(starter, BundleConstant.REQUEST_CODE); + } + + private static void putBundle(@NonNull Gist gistsModel, @NonNull Intent starter) { + String login = gistsModel.getOwner() != null ? gistsModel.getOwner().getLogin() : + gistsModel.getUser() != null ? gistsModel.getUser().getLogin() : ""; + starter.putExtras(Bundler.start() + .putParcelableArrayList(BundleConstant.ITEM, gistsModel.getFilesAsList()) + .put(BundleConstant.EXTRA, Login.getUser().getLogin().equalsIgnoreCase(login)) + .put(BundleConstant.ID, gistsModel.getGistId()) + .put(BundleConstant.EXTRA_TWO, gistsModel.getDescription()) + .end()); + } + + @OnClick(value = {R.id.createPublicGist, R.id.createSecretGist}) void onClick(View view) { + getPresenter().onSubmit(InputHelper.toString(description), + getFilesFragment().getFiles(), view.getId() == R.id.createPublicGist); + } + + @OnClick(R.id.addFile) public void onViewClicked() { + Logger.e(getFilesFragment()); + getFilesFragment().onAddNewFile(); } @Override public void onDescriptionError(boolean isEmptyDesc) { @@ -48,15 +82,16 @@ public class CreateGistActivity extends BaseActivity models = bundle.getParcelableArrayList(BundleConstant.ITEM); + boolean isOwner = bundle.getBoolean(BundleConstant.EXTRA); + id = bundle.getString(BundleConstant.ID); + String descriptionText = bundle.getString(BundleConstant.EXTRA_TWO); + if (description.getEditText() != null) description.getEditText().setText(descriptionText); + getFilesFragment().onInitFiles(models, isOwner); + } else { + getFilesFragment().onInitFiles(new ArrayList<>(), true); + } + } + buttonsHolder.setVisibility(!InputHelper.isEmpty(id) ? View.GONE : View.VISIBLE); } @Override public void onMessageDialogActionClicked(boolean isOk, @Nullable Bundle bundle) { @@ -110,21 +154,25 @@ public class CreateGistActivity extends BaseActivity files, boolean isPublic); void onSubmit(@NonNull CreateGistModel model); + + void onSubmitUpdate(@NonNull String id, @NonNull String description, @NonNull HashMap files); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistPresenter.java index 7b23af1b..71857912 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/create/CreateGistPresenter.java @@ -1,13 +1,9 @@ package com.fastaccess.ui.modules.gists.create; -import android.app.Activity; -import android.content.Intent; import android.support.annotation.NonNull; -import android.support.design.widget.TextInputLayout; import com.fastaccess.data.dao.CreateGistModel; import com.fastaccess.data.dao.FilesListModel; -import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.InputHelper; import com.fastaccess.provider.rest.RestProvider; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; @@ -19,38 +15,16 @@ import java.util.HashMap; */ class CreateGistPresenter extends BasePresenter implements CreateGistMvp.Presenter { - - @Override public void onActivityForResult(int resultCode, int requestCode, Intent intent) { - if (resultCode == Activity.RESULT_OK && requestCode == BundleConstant.REQUEST_CODE) { - if (intent != null && intent.getExtras() != null) { - CharSequence charSequence = intent.getExtras().getCharSequence(BundleConstant.EXTRA); - if (!InputHelper.isEmpty(charSequence)) { - sendToView(view -> view.onSetCode(charSequence)); - } - } - } - } - - @Override public void onSubmit(@NonNull TextInputLayout description, @NonNull TextInputLayout fileName, - @NonNull CharSequence fileContent, boolean isPublic) { + @Override public void onSubmit(@NonNull String description, @NonNull HashMap files, boolean isPublic) { boolean isEmptyDesc = InputHelper.isEmpty(description); - boolean isEmptyFileName = InputHelper.isEmpty(fileName); - boolean isEmptyFileContent = InputHelper.isEmpty(fileContent); if (getView() != null) { getView().onDescriptionError(isEmptyDesc); - getView().onFileNameError(isEmptyDesc); - getView().onFileContentError(isEmptyDesc); } - if (!isEmptyDesc && !isEmptyFileName && !isEmptyFileContent) { + if (!isEmptyDesc) { CreateGistModel createGistModel = new CreateGistModel(); createGistModel.setDescription(InputHelper.toString(description)); createGistModel.setPublicGist(isPublic); - HashMap modelHashMap = new HashMap<>(); - FilesListModel file = new FilesListModel(); - file.setFilename(InputHelper.toString(fileName)); - file.setContent(InputHelper.toString(fileContent)); - modelHashMap.put(InputHelper.toString(fileName), file); - createGistModel.setFiles(modelHashMap); + createGistModel.setFiles(files); onSubmit(createGistModel); } } @@ -59,4 +33,17 @@ class CreateGistPresenter extends BasePresenter implements C makeRestCall(RestProvider.getGistService(isEnterprise()).createGist(model), gistsModel -> sendToView(view -> view.onSuccessSubmission(gistsModel)), false); } + + @Override public void onSubmitUpdate(@NonNull String id, @NonNull String description, @NonNull HashMap files) { + boolean isEmptyDesc = InputHelper.isEmpty(description); + if (getView() != null) { + getView().onDescriptionError(isEmptyDesc); + } + if (isEmptyDesc) return; + CreateGistModel createGistModel = new CreateGistModel(); + createGistModel.setDescription(InputHelper.toString(description)); + createGistModel.setFiles(files); + makeRestCall(RestProvider.getGistService(isEnterprise()).editGist(createGistModel, id), + gistsModel -> sendToView(view -> view.onSuccessSubmission(gistsModel)), false); + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistBottomSheetDialog.kt b/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistBottomSheetDialog.kt new file mode 100644 index 00000000..12f7e6f4 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistBottomSheetDialog.kt @@ -0,0 +1,136 @@ +package com.fastaccess.ui.modules.gists.create.dialog + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.os.Parcelable +import android.support.design.widget.TextInputLayout +import android.support.v4.app.FragmentManager +import android.support.v7.widget.Toolbar +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.webkit.MimeTypeMap +import android.widget.EditText +import butterknife.BindView +import com.fastaccess.R +import com.fastaccess.data.dao.FilesListModel +import com.fastaccess.helper.BundleConstant +import com.fastaccess.helper.Bundler +import com.fastaccess.helper.InputHelper +import com.fastaccess.helper.ViewHelper +import com.fastaccess.provider.emoji.Emoji +import com.fastaccess.provider.markdown.MarkDownProvider +import com.fastaccess.ui.base.BaseDialogFragment +import com.fastaccess.ui.modules.gists.create.dialog.AddGistMvp.AddGistFileListener +import com.fastaccess.ui.widgets.markdown.MarkDownLayout +import com.fastaccess.ui.widgets.markdown.MarkdownEditText + +/** + * Created by kosh on 14/08/2017. + */ +class AddGistBottomSheetDialog : BaseDialogFragment(), AddGistMvp.View { + + @BindView(R.id.editText) lateinit var editText: MarkdownEditText + @BindView(R.id.description) lateinit var description: TextInputLayout + @BindView(R.id.toolbar) lateinit var toolbar: Toolbar + @BindView(R.id.markDownLayout) lateinit var markDownLayout: MarkDownLayout + + private var addFileListener: AddGistFileListener? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + when { + parentFragment is AddGistFileListener -> addFileListener = parentFragment as AddGistFileListener + context is AddGistFileListener -> addFileListener = context + else -> throw NullPointerException("${context::class.java.simpleName} most implement AddGistFileListener") + } + } + + override fun onDetach() { + addFileListener = null + super.onDetach() + } + + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { + dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun providePresenter(): AddGistPresenter = AddGistPresenter() + + override fun onAppendLink(title: String?, link: String?, isLink: Boolean) { + if (isLink) { + MarkDownProvider.addLink(editText, InputHelper.toString(title), InputHelper.toString(link)) + } else { + editText.setText(String.format("%s\n", editText.text)) + MarkDownProvider.addPhoto(editText, InputHelper.toString(title), InputHelper.toString(link)) + } + } + + override fun fragmentLayout(): Int = R.layout.add_gist_file_layout + + override fun getEditText(): EditText = editText + + override fun fragmentManager(): FragmentManager = childFragmentManager + + override fun getSavedText(): CharSequence? = editText.savedText + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + markDownLayout.markdownListener = this + var file = arguments?.getParcelable(BundleConstant.ITEM) + val position = arguments?.getInt(BundleConstant.ID) + if (position != null) { + toolbar.title = if (position > 0) getString(R.string.edit_gist) else getString(R.string.create_gist) + } else { + toolbar.title = getString(R.string.create_gist) + } + editText.setOnFocusChangeListener { _, focused -> markDownLayout.visibility = if (focused) View.VISIBLE else View.GONE } + toolbar.inflateMenu(R.menu.done_menu) + toolbar.menu.findItem(R.id.submit)?.setIcon(R.drawable.ic_done) + toolbar.setNavigationIcon(R.drawable.ic_clear) + toolbar.setNavigationOnClickListener { dismiss() } + toolbar.setOnMenuItemClickListener { + if (it.itemId == R.id.submit) { + if (file == null) { + file = FilesListModel() + } + file?.let { + it.content = getSavedText().toString() + it.filename = InputHelper.toString(description) + it.type = MimeTypeMap.getFileExtensionFromUrl(file!!.filename) + it.size = it.content?.length?.toLong() + ViewHelper.hideKeyboard(editText) + addFileListener?.onFileAdded(it, position) + } + } + dismiss() + return@setOnMenuItemClickListener true + } + file?.let { + description.editText?.setText(it.filename) + editText.setText(it.content) + } + } + + @SuppressLint("SetTextI18n") + override fun onEmojiAdded(emoji: Emoji?) { + markDownLayout.onEmojiAdded(emoji) + } + + companion object { + val TAG = AddGistBottomSheetDialog::class.java.simpleName!! + + fun newInstance(file: FilesListModel?, position: Int = -1): AddGistBottomSheetDialog { + val fragment = AddGistBottomSheetDialog() + file?.let { + fragment.arguments = Bundler.start() + .put(BundleConstant.ITEM, file as Parcelable) + .put(BundleConstant.ID, position) + .end() + } + return fragment + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistMvp.kt b/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistMvp.kt new file mode 100644 index 00000000..228f9198 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistMvp.kt @@ -0,0 +1,19 @@ +package com.fastaccess.ui.modules.gists.create.dialog + +import com.fastaccess.data.dao.FilesListModel +import com.fastaccess.ui.base.mvp.BaseMvp +import com.fastaccess.ui.modules.editor.emoji.EmojiMvp +import com.fastaccess.ui.modules.editor.popup.EditorLinkImageMvp +import com.fastaccess.ui.widgets.markdown.MarkDownLayout + +/** + * Created by kosh on 14/08/2017. + */ +interface AddGistMvp { + + interface View : BaseMvp.FAView, EditorLinkImageMvp.EditorLinkCallback, MarkDownLayout.MarkdownListener, EmojiMvp.EmojiCallback + interface Presenter + interface AddGistFileListener { + fun onFileAdded(file: FilesListModel, position: Int? = -1) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistPresenter.kt new file mode 100644 index 00000000..7329e6e1 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/create/dialog/AddGistPresenter.kt @@ -0,0 +1,8 @@ +package com.fastaccess.ui.modules.gists.create.dialog + +import com.fastaccess.ui.base.mvp.presenter.BasePresenter + +/** + * Created by kosh on 14/08/2017. + */ +class AddGistPresenter : BasePresenter(), AddGistMvp.Presenter \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java index 139ada5d..d4e53092 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java @@ -17,18 +17,23 @@ import android.view.View; import com.fastaccess.R; import com.fastaccess.data.dao.FragmentPagerAdapterModel; import com.fastaccess.data.dao.model.Gist; +import com.fastaccess.data.dao.model.Login; import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; import com.fastaccess.helper.InputHelper; import com.fastaccess.helper.ParseDateFormat; +import com.fastaccess.helper.PrefGetter; import com.fastaccess.helper.ViewHelper; import com.fastaccess.provider.scheme.LinkParserHelper; import com.fastaccess.provider.tasks.git.GithubActionService; import com.fastaccess.ui.adapter.FragmentsPagerAdapter; import com.fastaccess.ui.base.BaseActivity; import com.fastaccess.ui.base.BaseFragment; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; +import com.fastaccess.ui.modules.gists.create.CreateGistActivity; import com.fastaccess.ui.modules.gists.gist.comments.GistCommentsFragment; +import com.fastaccess.ui.modules.main.premium.PremiumActivity; import com.fastaccess.ui.widgets.AvatarLayout; import com.fastaccess.ui.widgets.FontTextView; import com.fastaccess.ui.widgets.ForegroundImageView; @@ -55,8 +60,10 @@ public class GistActivity extends BaseActivity @BindView(R.id.startGist) ForegroundImageView startGist; @BindView(R.id.forkGist) ForegroundImageView forkGist; @BindView(R.id.detailsIcon) View detailsIcon; + @BindView(R.id.edit) View edit; private int accentColor; private int iconColor; + private CommentEditorFragment commentEditorFragment; public static Intent createIntent(@NonNull Context context, @NonNull String gistId, boolean isEnterprise) { Intent intent = new Intent(context, GistActivity.class); @@ -67,15 +74,6 @@ public class GistActivity extends BaseActivity return intent; } - @OnClick(R.id.fab) void onAddComment() { - if (pager != null && pager.getAdapter() != null) { - GistCommentsFragment view = (GistCommentsFragment) pager.getAdapter().instantiateItem(pager, 1); - if (view != null) { - view.onStartNewComment(); - } - } - } - @OnClick(R.id.detailsIcon) void onTitleClick() { if (getPresenter().getGist() != null && !InputHelper.isEmpty(getPresenter().getGist().getDescription())) MessageDialogView.newInstance(getString(R.string.details), getPresenter().getGist().getDescription(), false, true) @@ -104,6 +102,14 @@ public class GistActivity extends BaseActivity } } + @OnClick(R.id.edit) void onEdit() { + if (PrefGetter.isProEnabled() || PrefGetter.isAllFeaturesUnlocked()) { + if (getPresenter().getGist() != null) CreateGistActivity.start(this, getPresenter().getGist()); + } else { + PremiumActivity.Companion.startActivity(this); + } + } + @Override protected int layout() { return R.layout.gists_pager_layout; } @@ -126,6 +132,8 @@ public class GistActivity extends BaseActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + fab.hide(); + commentEditorFragment = (CommentEditorFragment) getSupportFragmentManager().findFragmentById(R.id.commentFragment); accentColor = ViewHelper.getAccentColor(this); iconColor = ViewHelper.getIconColor(this); if (savedInstanceState == null) { @@ -173,6 +181,15 @@ public class GistActivity extends BaseActivity } } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + if (requestCode == BundleConstant.REQUEST_CODE) { + getPresenter().callApi(); + } + } + } + @Override public void onSuccessDeleted() { hideProgress(); if (getPresenter().getGist() != null) { @@ -213,6 +230,7 @@ public class GistActivity extends BaseActivity avatarLayout.setUrl(url, login, false, LinkParserHelper.isEnterprise(gistsModel.getHtmlUrl())); title.setText(gistsModel.getDisplayTitle(false, true)); setTaskName(gistsModel.getDisplayTitle(false, true).toString()); + edit.setVisibility(Login.getUser().getLogin().equals(login) ? View.VISIBLE : View.GONE); detailsIcon.setVisibility(InputHelper.isEmpty(gistsModel.getDescription()) || !ViewHelper.isEllipsed(title) ? View.GONE : View.VISIBLE); if (gistsModel.getCreatedAt().before(gistsModel.getUpdatedAt())) { date.setText(String.format("%s %s", ParseDateFormat.getTimeAgo(gistsModel.getCreatedAt()), getString(R.string.edited))); @@ -248,11 +266,28 @@ public class GistActivity extends BaseActivity } } - private void hideShowFab() { - if (pager.getCurrentItem() == 1) { - fab.show(); - } else { - fab.hide(); + @Override public void onSendActionClicked(@NonNull String text, Bundle bundle) { + if (pager == null || pager.getAdapter() == null) return; + GistCommentsFragment view = (GistCommentsFragment) pager.getAdapter().instantiateItem(pager, 1); + if (view != null) { + view.onHandleComment(text, bundle); } } + + @Override public void onTagUser(@NonNull String username) { + commentEditorFragment.onAddUserName(username); + } + + + private void hideShowFab() { + if (pager.getCurrentItem() == 1) { + getSupportFragmentManager().beginTransaction().show(commentEditorFragment).commit(); + } else { + getSupportFragmentManager().beginTransaction().hide(commentEditorFragment).commit(); + } + } + + @Override public void onCreateComment(String text, Bundle bundle) { + + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistMvp.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistMvp.java index 302ec981..e6e0afca 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistMvp.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistMvp.java @@ -6,6 +6,7 @@ import android.support.annotation.Nullable; import com.fastaccess.data.dao.model.Gist; import com.fastaccess.ui.base.mvp.BaseMvp; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; /** * Created by Kosh on 12 Nov 2016, 12:17 PM @@ -13,7 +14,7 @@ import com.fastaccess.ui.base.mvp.BaseMvp; interface GistMvp { - interface View extends BaseMvp.FAView { + interface View extends BaseMvp.FAView, CommentEditorFragment.CommentListener { void onSuccessDeleted(); void onErrorDeleting(); @@ -47,6 +48,8 @@ interface GistMvp { void checkStarring(@NonNull String gistId); + void callApi(); + void onWorkOffline(@NonNull String gistId); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistPresenter.java index fb96e228..3191784e 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistPresenter.java @@ -8,6 +8,7 @@ import android.support.annotation.Nullable; import com.fastaccess.data.dao.model.Gist; import com.fastaccess.data.dao.model.Login; import com.fastaccess.helper.BundleConstant; +import com.fastaccess.helper.InputHelper; import com.fastaccess.helper.RxHelper; import com.fastaccess.provider.rest.RestProvider; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; @@ -40,11 +41,7 @@ class GistPresenter extends BasePresenter implements GistMvp.Prese checkStarring(gist.getGistId()); sendToView(GistMvp.View::onSetupDetails); } else if (gistId != null) { - checkStarring(gistId); - makeRestCall(RestProvider.getGistService(isEnterprise()).getGist(gistId), gistsModel -> { - this.gist = gistsModel; - sendToView(GistMvp.View::onSetupDetails); - }); + callApi(); } else { sendToView(GistMvp.View::onSetupDetails); } @@ -61,9 +58,7 @@ class GistPresenter extends BasePresenter implements GistMvp.Prese sendToView(GistMvp.View::onErrorDeleting); } }) - .subscribe(booleanResponse -> {/**/}, throwable -> { - sendToView(view -> view.showErrorMessage(throwable.getMessage())); - })); + .subscribe(booleanResponse -> {/**/}, throwable -> sendToView(view -> view.showErrorMessage(throwable.getMessage())))); } @Override public boolean isOwner() { @@ -106,4 +101,14 @@ class GistPresenter extends BasePresenter implements GistMvp.Prese })); } } + + @Override public void callApi() { + if (!InputHelper.isEmpty(gistId)) { + checkStarring(gistId); + makeRestCall(RestProvider.getGistService(isEnterprise()).getGist(gistId), gistsModel -> { + this.gist = gistsModel; + sendToView(GistMvp.View::onSetupDetails); + }); + } + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/comments/GistCommentsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/comments/GistCommentsFragment.java index f7b11b34..64870fa7 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/comments/GistCommentsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/comments/GistCommentsFragment.java @@ -1,6 +1,7 @@ package com.fastaccess.ui.modules.gists.gist.comments; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; @@ -22,16 +23,17 @@ import com.fastaccess.provider.timeline.CommentsHelper; import com.fastaccess.ui.adapter.CommentsAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.editor.EditorActivity; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; import butterknife.BindView; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.EDIT_GIST_COMMENT_EXTRA; -import static com.fastaccess.helper.BundleConstant.ExtraTYpe.NEW_GIST_COMMENT_EXTRA; +import static com.fastaccess.helper.BundleConstant.ExtraType.EDIT_GIST_COMMENT_EXTRA; /** * Created by Kosh on 11 Nov 2016, 12:36 PM @@ -42,7 +44,9 @@ public class GistCommentsFragment extends BaseFragment onLoadMore; @@ -53,6 +57,23 @@ public class GistCommentsFragment extends BaseFragment implemen super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } if (page > lastPage || parameter == null || lastPage == 0) { sendToView(GistCommentsMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); makeRestCall(RestProvider.getGistService(isEnterprise()).getGistComments(parameter, page), @@ -68,6 +69,7 @@ class GistCommentsPresenter extends BasePresenter implemen } sendToView(view -> view.onNotifyAdapter(listResponse.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getComments() { @@ -102,6 +104,13 @@ class GistCommentsPresenter extends BasePresenter implemen } } + @Override public void onHandleComment(@NonNull String text, @Nullable Bundle bundle, String gistId) { + CommentRequestModel model = new CommentRequestModel(); + model.setBody(text); + makeRestCall(RestProvider.getGistService(isEnterprise()).createGistComment(gistId, model), + comment -> sendToView(view -> view.onAddNewComment(comment))); + } + @Override public void onItemClick(int position, View v, Comment item) { if (getView() == null) return; if (v.getId() == R.id.toggle || v.getId() == R.id.toggleHolder) { @@ -126,10 +135,14 @@ class GistCommentsPresenter extends BasePresenter implemen } @Override public void onItemLongClick(int position, View v, Comment item) { - if (item.getUser() != null && TextUtils.equals(item.getUser().getLogin(), Login.getUser().getLogin())) { - if (getView() != null) getView().onShowDeleteMsg(item.getId()); + if (v.getId() == R.id.toggle) { + if (getView() != null) getView().onReply(item.getUser(), item.getBody()); } else { - onItemClick(position, v, item); + if (item.getUser() != null && TextUtils.equals(item.getUser().getLogin(), Login.getUser().getLogin())) { + if (getView() != null) getView().onShowDeleteMsg(item.getId()); + } else { + onItemClick(position, v, item); + } } } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListFragment.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListFragment.java index 705a5486..c87109af 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListFragment.java @@ -6,24 +6,30 @@ import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.view.View; +import com.evernote.android.state.State; import com.fastaccess.R; import com.fastaccess.data.dao.FilesListModel; -import com.fastaccess.data.dao.GithubFileModel; import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; import com.fastaccess.helper.FileHelper; import com.fastaccess.helper.InputHelper; +import com.fastaccess.helper.Logger; +import com.fastaccess.helper.PrefGetter; import com.fastaccess.provider.markdown.MarkDownProvider; import com.fastaccess.provider.rest.RestProvider; import com.fastaccess.ui.adapter.GistFilesAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.code.CodeViewerActivity; +import com.fastaccess.ui.modules.gists.create.dialog.AddGistBottomSheetDialog; +import com.fastaccess.ui.modules.main.premium.PremiumActivity; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.ArrayList; +import java.util.HashMap; import butterknife.BindView; @@ -37,11 +43,15 @@ public class GistFilesListFragment extends BaseFragment files, boolean isOwner) { GistFilesListFragment view = new GistFilesListFragment(); view.setArguments(Bundler.start() - .putParcelableArrayList(BundleConstant.ITEM, new ArrayList<>(gistsModel.values())) + .putParcelableArrayList(BundleConstant.ITEM, files) + .put(BundleConstant.EXTRA_TYPE, isOwner) .end()); return view; } @@ -55,30 +65,65 @@ public class GistFilesListFragment extends BaseFragment filesListModel = getArguments().getParcelableArrayList(BundleConstant.ITEM); - stateLayout.hideReload(); stateLayout.setEmptyText(R.string.no_files); - recycler.setEmptyView(stateLayout); + stateLayout.showEmptyState(); + recycler.setEmptyView(stateLayout, refresh); refresh.setEnabled(false); - if (filesListModel == null) { - return; + adapter = new GistFilesAdapter(getPresenter().getFiles(), getPresenter(), isOwner); + recycler.setAdapter(adapter); + if (getArguments() != null && savedInstanceState == null) { + ArrayList filesListModel = getArguments().getParcelableArrayList(BundleConstant.ITEM); + isOwner = getArguments().getBoolean(BundleConstant.EXTRA_TYPE); + onInitFiles(filesListModel, isOwner); + setArguments(null);//CLEAR + } else { + onInitFiles(getPresenter().getFiles(), isOwner); } - if (!filesListModel.isEmpty()) { - recycler.setAdapter(new GistFilesAdapter(filesListModel, getPresenter())); + fastScroller.attachRecyclerView(recycler); + } + + @Override public void onOpenFile(@NonNull FilesListModel item, int position) { + if (canOpen(item) && !isOwner) { + CodeViewerActivity.startActivity(getContext(), item.getRawUrl(), item.getRawUrl()); + } else if (isOwner && canOpen(item)) { + onEditFile(item, position); } } - @Override public void onOpenFile(@NonNull FilesListModel item) { - if (item.getRawUrl() != null) { - if (item.getSize() > FileHelper.ONE_MB && !MarkDownProvider.isImage(item.getRawUrl())) { - MessageDialogView.newInstance(getString(R.string.big_file), getString(R.string.big_file_description), false, true, - Bundler.start().put(BundleConstant.YES_NO_EXTRA, true).put(BundleConstant.EXTRA, item.getRawUrl()).end()) - .show(getChildFragmentManager(), "MessageDialogView"); - } else { - CodeViewerActivity.startActivity(getContext(), item.getRawUrl(), item.getRawUrl()); + @Override public void onDeleteFile(@NonNull FilesListModel item, int position) { + MessageDialogView.newInstance(getString(R.string.delete), getString(R.string.confirm_message), false, + Bundler.start() + .put(BundleConstant.ID, position) + .put(BundleConstant.YES_NO_EXTRA, true) + .end()) + .show(getChildFragmentManager(), MessageDialogView.TAG); + } + + @Override public void onEditFile(@NonNull FilesListModel item, int position) { + AddGistBottomSheetDialog.Companion.newInstance(item, position).show(getChildFragmentManager(), AddGistBottomSheetDialog.Companion.getTAG()); + } + + @Override public void onInitFiles(@Nullable ArrayList filesListModel, boolean isOwner) { + if (filesListModel == null) { + filesListModel = new ArrayList<>();//DO NOT PASS NULL TO ADAPTER + } + if (getPresenter().getFilesMap().isEmpty()) { + for (FilesListModel listModel : filesListModel) { + getPresenter().getFilesMap().put(listModel.getFilename(), listModel); } + } + adapter.setOwner(isOwner); + getPresenter().onSetList(filesListModel); + adapter.insertItems(filesListModel); + } + + @Override public void onAddNewFile() { + Logger.e("Hello world"); + if (adapter.getItemCount() == 0 || (PrefGetter.isProEnabled() || PrefGetter.isAllFeaturesUnlocked())) { + AddGistBottomSheetDialog.Companion.newInstance(null, -1) + .show(getChildFragmentManager(), AddGistBottomSheetDialog.Companion.getTAG()); } else { - showErrorMessage(getString(R.string.no_url)); + PremiumActivity.Companion.startActivity(getContext()); } } @@ -90,6 +135,19 @@ public class GistFilesListFragment extends BaseFragment FileHelper.ONE_MB && !MarkDownProvider.isImage(item.getRawUrl())) { + MessageDialogView.newInstance(getString(R.string.big_file), getString(R.string.big_file_description), false, true, + Bundler.start().put(BundleConstant.YES_NO_EXTRA, true).put(BundleConstant.EXTRA, item.getRawUrl()).end()) + .show(getChildFragmentManager(), "MessageDialogView"); + return false; + } + return true; + } + + @NonNull @Override public HashMap getFiles() { + return getPresenter().getFilesMap(); + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListMvp.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListMvp.java index 91cde58e..cbda030a 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListMvp.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListMvp.java @@ -1,20 +1,39 @@ package com.fastaccess.ui.modules.gists.gist.files; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.fastaccess.data.dao.FilesListModel; import com.fastaccess.ui.base.mvp.BaseMvp; +import com.fastaccess.ui.modules.gists.create.dialog.AddGistMvp; import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; +import java.util.ArrayList; +import java.util.HashMap; + /** * Created by Kosh on 13 Nov 2016, 1:35 PM */ -interface GistFilesListMvp { +public interface GistFilesListMvp { - interface View extends BaseMvp.FAView { - void onOpenFile(@NonNull FilesListModel item); + interface View extends BaseMvp.FAView, AddGistMvp.AddGistFileListener { + void onOpenFile(@NonNull FilesListModel item, int position); + + void onDeleteFile(@NonNull FilesListModel item, int position); + + void onEditFile(@NonNull FilesListModel item, int position); + + void onInitFiles(@Nullable ArrayList file, boolean isOwner); + + void onAddNewFile(); + + @NonNull HashMap getFiles(); } - interface Presenter extends BaseMvp.FAPresenter, BaseViewHolder.OnItemClickListener {} + interface Presenter extends BaseMvp.FAPresenter, BaseViewHolder.OnItemClickListener { + void onSetList(@Nullable ArrayList files); + + @NonNull ArrayList getFiles(); + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListPresenter.java index 6df48a7f..7b94da52 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/files/GistFilesListPresenter.java @@ -1,19 +1,48 @@ package com.fastaccess.ui.modules.gists.gist.files; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.View; +import com.fastaccess.R; import com.fastaccess.data.dao.FilesListModel; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; +import java.util.ArrayList; +import java.util.HashMap; + +import lombok.Getter; + /** * Created by Kosh on 13 Nov 2016, 1:35 PM */ -class GistFilesListPresenter extends BasePresenter implements GistFilesListMvp.Presenter { +public class GistFilesListPresenter extends BasePresenter implements GistFilesListMvp.Presenter { + private ArrayList listModels; + @Getter private HashMap filesMap = new HashMap<>(); @Override public void onItemClick(int position, View v, FilesListModel item) { - if (getView() != null) getView().onOpenFile(item); + if (getView() != null) { + if (v.getId() == R.id.delete) { + getView().onDeleteFile(item, position); + } else if (v.getId() == R.id.edit) { + getView().onEditFile(item, position); + } else { + getView().onOpenFile(item, position); + } + } } @Override public void onItemLongClick(int position, View v, FilesListModel item) {} + + @Override public void onSetList(@Nullable ArrayList files) { + this.listModels = files; + } + + @NonNull @Override public ArrayList getFiles() { + if (listModels == null) { + return new ArrayList<>(); + } + return listModels; + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/login/chooser/LoginChooserActivity.kt b/app/src/main/java/com/fastaccess/ui/modules/login/chooser/LoginChooserActivity.kt index 6e9a8303..6bd8318e 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/login/chooser/LoginChooserActivity.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/login/chooser/LoginChooserActivity.kt @@ -7,6 +7,7 @@ import android.support.design.widget.CoordinatorLayout import android.support.transition.TransitionManager import android.view.View import android.widget.RelativeLayout +import butterknife.BindView import butterknife.OnClick import com.fastaccess.BuildConfig import com.fastaccess.R @@ -16,10 +17,8 @@ import com.fastaccess.helper.PrefGetter import com.fastaccess.ui.adapter.LoginAdapter import com.fastaccess.ui.base.BaseActivity import com.fastaccess.ui.modules.login.LoginActivity -import com.fastaccess.ui.modules.main.donation.CheckPurchaseActivity import com.fastaccess.ui.modules.main.premium.PremiumActivity import com.fastaccess.ui.modules.settings.LanguageBottomSheetDialog -import com.fastaccess.ui.widgets.bindView import com.fastaccess.ui.widgets.dialog.MessageDialogView import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView import io.reactivex.functions.Action @@ -31,12 +30,13 @@ import java.util.* class LoginChooserActivity : BaseActivity(), LoginChooserMvp.View { - val language_selector: RelativeLayout by bindView(R.id.language_selector) - val recycler: DynamicRecyclerView by bindView(R.id.recycler) - val multiAccLayout: View by bindView(R.id.multiAccLayout) - val viewGroup: CoordinatorLayout by bindView(R.id.viewGroup) - val toggleImage: View by bindView(R.id.toggleImage) - val adapter = LoginAdapter() + @BindView(R.id.language_selector) lateinit var language_selector: RelativeLayout + @BindView(R.id.recycler) lateinit var recycler: DynamicRecyclerView + @BindView(R.id.multiAccLayout) lateinit var multiAccLayout: View + @BindView(R.id.viewGroup) lateinit var viewGroup: CoordinatorLayout + @BindView(R.id.toggleImage) lateinit var toggleImage: View + + private val adapter = LoginAdapter() override fun layout(): Int = R.layout.login_chooser_layout @@ -123,7 +123,7 @@ class LoginChooserActivity : BaseActivity impl @Override public boolean onPrepareOptionsMenu(Menu menu) { if (isLoggedIn() && Notification.hasUnreadNotifications()) { ViewHelper.tintDrawable(menu.findItem(R.id.notifications).setIcon(R.drawable.ic_ring).getIcon(), ViewHelper.getAccentColor(this)); + } else { + ViewHelper.tintDrawable(menu.findItem(R.id.notifications).setIcon(R.drawable.ic_notifications_none).getIcon(), ViewHelper.getIconColor + (this)); } return super.onPrepareOptionsMenu(menu); } diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/MainPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/main/MainPresenter.java index 51dfae1f..31a86374 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/MainPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/main/MainPresenter.java @@ -7,7 +7,6 @@ import android.support.v4.app.FragmentManager; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; -import com.annimon.stream.Stream; import com.fastaccess.R; import com.fastaccess.data.dao.model.Login; import com.fastaccess.data.dao.model.Notification; @@ -20,7 +19,7 @@ import com.fastaccess.ui.modules.feeds.FeedsFragment; import com.fastaccess.ui.modules.main.issues.pager.MyIssuesPagerFragment; import com.fastaccess.ui.modules.main.pullrequests.pager.MyPullsPagerFragment; -import io.reactivex.Observable; +import io.reactivex.Single; import static com.fastaccess.helper.ActivityHelper.getVisibleFragment; import static com.fastaccess.helper.AppHelper.getFragmentByTag; @@ -47,17 +46,16 @@ public class MainPresenter extends BasePresenter implements MainMv }) .flatMap(login -> RxHelper.getObservable(RestProvider.getNotificationService(isEnterprise()) .getNotifications(ParseDateFormat.getLastWeekDate()))) - .flatMap(notificationPageable -> { - if (notificationPageable != null && notificationPageable.getItems() == null && !notificationPageable.getItems().isEmpty()) { - manageDisposable(Notification.save(notificationPageable.getItems())); - return Observable.just(Stream.of(notificationPageable.getItems()).anyMatch(Notification::isUnread)); + .flatMapSingle(notificationPageable -> { + if (notificationPageable != null) { + return Notification.saveAsSingle(notificationPageable.getItems()); } - return Observable.empty(); + return Single.just(true); }) - .subscribe(unread -> sendToView(view -> { + .subscribe(unread -> {/**/}, Throwable::printStackTrace/*fail silently*/, () -> sendToView(view -> { view.onInvalidateNotification(); view.onUpdateDrawerMenuHeader(); - }), Throwable::printStackTrace/*fail silently*/)); + }))); } @Override public boolean canBackPress(@NonNull DrawerLayout drawerLayout) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonateActivity.kt b/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonateActivity.kt index 5ac0da2f..f46a2fb8 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonateActivity.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonateActivity.kt @@ -5,11 +5,10 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.support.v4.app.Fragment -import com.crashlytics.android.answers.Answers -import com.crashlytics.android.answers.PurchaseEvent import com.fastaccess.BuildConfig import com.fastaccess.R import com.fastaccess.helper.* +import com.fastaccess.provider.fabric.FabricProvider import com.fastaccess.ui.base.BaseActivity import com.fastaccess.ui.base.mvp.BaseMvp import com.fastaccess.ui.base.mvp.presenter.BasePresenter @@ -46,7 +45,7 @@ class DonateActivity : BaseActivity if (throwable == null) { - Answers.getInstance().logPurchase(PurchaseEvent().putItemName(productKey).putSuccess(true)) + FabricProvider.logPurchase(productKey) showMessage(R.string.success, R.string.success_purchase_message) enableProduct(productKey, applicationContext) val intent = Intent() diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonationActivity.java b/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonationActivity.java index 5170701f..5d6fe076 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonationActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/main/donation/DonationActivity.java @@ -81,11 +81,11 @@ public class DonationActivity extends BaseActivity { if (AppHelper.isGoogleAvailable(this)) { DonateActivity.Companion.start(this, productKey); } else { - showErrorMessage(getString(R.string.common_google_play_services_unsupported_text)); + showErrorMessage(getString(R.string.google_play_service_error)); } } - protected void checkPurchase() { + private void checkPurchase() { ((BasePresenter) getPresenter()).manageViewDisposable(RxBillingService.getInstance(this, BuildConfig.DEBUG) .getPurchases(ProductType.IN_APP) .subscribe((purchases, throwable) -> { diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/issues/MyIssuesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/main/issues/MyIssuesFragment.java index 5fc16b36..a46784cb 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/issues/MyIssuesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/main/issues/MyIssuesFragment.java @@ -22,6 +22,7 @@ import com.fastaccess.ui.modules.repos.RepoPagerMvp; import com.fastaccess.ui.modules.repos.extras.popup.IssuePopupFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -36,6 +37,7 @@ public class MyIssuesFragment extends BaseFragment onLoadMore; private IssuesAdapter adapter; @@ -137,6 +139,7 @@ public class MyIssuesFragment extends BaseFragment implement this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable IssueState parameter) { + @Override public boolean onCallApi(int page, @Nullable IssueState parameter) { if (parameter == null) { throw new NullPointerException("parameter is null"); } @@ -75,7 +75,7 @@ public class MyIssuesPresenter extends BasePresenter implement } if (page > lastPage || lastPage == 0) { sendToView(MyIssuesMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); makeRestCall(RestProvider.getIssueService(isEnterprise()).getIssuesWithCount(getUrl(parameter), page), issues -> { @@ -85,6 +85,7 @@ public class MyIssuesPresenter extends BasePresenter implement } sendToView(view -> view.onNotifyAdapter(issues.getItems(), page)); }); + return true; } @NonNull private String getUrl(@NonNull IssueState parameter) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/orgs/OrgListDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/main/orgs/OrgListDialogFragment.java index 7129ea1b..f96e2e09 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/orgs/OrgListDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/main/orgs/OrgListDialogFragment.java @@ -15,6 +15,7 @@ import com.fastaccess.ui.base.BaseDialogFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -31,6 +32,7 @@ public class OrgListDialogFragment extends BaseDialogFragment(), PremiumMvp.View { - val editText: EditText by bindView(R.id.editText) - val progressLayout: View by bindView(R.id.progressLayout) - val viewGroup: FrameLayout by bindView(R.id.viewGroup) + @BindView(R.id.editText) lateinit var editText: EditText + @BindView(R.id.viewGroup) lateinit var viewGroup: FrameLayout + @BindView(R.id.progressLayout) lateinit var progressLayout: View override fun layout(): Int = R.layout.pro_features_layout @@ -88,7 +87,7 @@ class PremiumActivity : BaseActivity(), Premi } override fun onSuccessfullyActivated() { - Answers.getInstance().logPurchase(PurchaseEvent().putItemName(InputHelper.toString(editText)).putSuccess(true)) + FabricProvider.logPurchase(InputHelper.toString(editText)) PrefGetter.setProItems() PrefGetter.setEnterpriseItem() showMessage(R.string.success, R.string.success) @@ -114,7 +113,7 @@ class PremiumActivity : BaseActivity(), Premi if (AppHelper.isGoogleAvailable(this)) { return true } - showErrorMessage(getString(R.string.common_google_play_services_unsupported_text)) + showErrorMessage(getString(R.string.google_play_service_error)) return false } diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt index 3187a191..ab1cb8f8 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt @@ -29,7 +29,7 @@ class PremiumPresenter : BasePresenter(), PremiumMvp.Presenter Logger.e(it.children, it.childrenCount, exists) return@flatMap Observable.just(exists) } - .doFinally { sendToView { it.hideProgress() } } + .doOnComplete { sendToView { it.hideProgress() } } .subscribe({ when (it) { true -> sendToView { it.onSuccessfullyActivated() } diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/pullrequests/MyPullRequestFragment.java b/app/src/main/java/com/fastaccess/ui/modules/main/pullrequests/MyPullRequestFragment.java index 67da68c1..970a2f18 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/main/pullrequests/MyPullRequestFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/main/pullrequests/MyPullRequestFragment.java @@ -22,6 +22,7 @@ import com.fastaccess.ui.modules.repos.RepoPagerMvp; import com.fastaccess.ui.modules.repos.extras.popup.IssuePopupFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -36,6 +37,7 @@ public class MyPullRequestFragment extends BaseFragment onLoadMore; private PullRequestAdapter adapter; @@ -155,6 +157,7 @@ public class MyPullRequestFragment extends BaseFragment lastPage || lastPage == 0) { sendToView(MyPullRequestsMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); makeRestCall(RestProvider.getPullRequestService(isEnterprise()).getPullsWithCount(getUrl(parameter), page), response -> { @@ -85,6 +85,7 @@ public class MyPullRequestsPresenter extends BasePresenter view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @NonNull private String getUrl(@NonNull IssueState parameter) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/notification/all/AllNotificationsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/notification/all/AllNotificationsFragment.java index a9f021d7..5340e6e0 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/notification/all/AllNotificationsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/notification/all/AllNotificationsFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.R; import com.fastaccess.data.dao.GroupedNotificationModel; import com.fastaccess.data.dao.model.Notification; import com.fastaccess.data.dao.model.Repo; +import com.fastaccess.helper.Bundler; import com.fastaccess.helper.ObjectsCompat; import com.fastaccess.provider.scheme.SchemeParser; import com.fastaccess.provider.tasks.notification.ReadNotificationService; @@ -25,7 +26,9 @@ import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.notification.callback.OnNotificationChangedListener; import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; +import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -41,6 +44,7 @@ public class AllNotificationsFragment extends BaseFragment implements AllNotificationsMvp.Presenter { - private ArrayList notifications = new ArrayList<>(); + private final ArrayList notifications = new ArrayList<>(); @Override public void onItemClick(int position, View v, GroupedNotificationModel model) { if (getView() == null) return; @@ -111,7 +111,7 @@ public class AllNotificationsPresenter extends BasePresenter sendToView(BaseMvp.FAView::hideProgress)), response -> sendToView(view -> view.onNotifyAdapter + makeRestCall(observable.doOnComplete(() -> sendToView(BaseMvp.FAView::hideProgress)), response -> sendToView(view -> view.onNotifyAdapter (response))); } diff --git a/app/src/main/java/com/fastaccess/ui/modules/notification/unread/UnreadNotificationsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/notification/unread/UnreadNotificationsFragment.java index da812f5c..fb5962b6 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/notification/unread/UnreadNotificationsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/notification/unread/UnreadNotificationsFragment.java @@ -14,6 +14,7 @@ import android.view.View; import com.fastaccess.R; import com.fastaccess.data.dao.GroupedNotificationModel; import com.fastaccess.data.dao.model.Notification; +import com.fastaccess.helper.Bundler; import com.fastaccess.provider.scheme.SchemeParser; import com.fastaccess.provider.tasks.notification.ReadNotificationService; import com.fastaccess.ui.adapter.NotificationsAdapter; @@ -22,7 +23,9 @@ import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.notification.callback.OnNotificationChangedListener; import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; +import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -37,6 +40,7 @@ public class UnreadNotificationsFragment extends BaseFragment onLoadMore; private UsersAdapter adapter; @@ -73,6 +75,7 @@ public class ProfileFollowersFragment extends BaseFragment super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -58,7 +58,7 @@ class ProfileFollowersPresenter extends BasePresenter setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(ProfileFollowersMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getUserService(isEnterprise()).getFollowers(parameter, page), response -> { @@ -68,6 +68,7 @@ class ProfileFollowersPresenter extends BasePresenter } sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getFollowers() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/following/ProfileFollowingFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/following/ProfileFollowingFragment.java index a0abfb4b..3da3b821 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/following/ProfileFollowingFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/following/ProfileFollowingFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.UsersAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,6 +31,7 @@ public class ProfileFollowingFragment extends BaseFragment onLoadMore; private UsersAdapter adapter; @@ -73,6 +75,7 @@ public class ProfileFollowingFragment extends BaseFragment super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -58,7 +58,7 @@ class ProfileFollowingPresenter extends BasePresenter setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(ProfileFollowingMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getUserService(isEnterprise()).getFollowing(parameter, page), response -> { @@ -68,6 +68,7 @@ class ProfileFollowingPresenter extends BasePresenter } sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getFollowing() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/gists/ProfileGistsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/gists/ProfileGistsFragment.java index f305d714..ab3e18d6 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/gists/ProfileGistsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/gists/ProfileGistsFragment.java @@ -20,6 +20,7 @@ import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.gists.gist.GistActivity; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -34,6 +35,7 @@ public class ProfileGistsFragment extends BaseFragment onLoadMore; @@ -68,6 +70,7 @@ public class ProfileGistsFragment extends BaseFragment implemen super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -59,7 +59,7 @@ class ProfileGistsPresenter extends BasePresenter implemen setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(ProfileGistsMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getGistService(isEnterprise()).getUserGists(parameter, page), listResponse -> { @@ -67,6 +67,7 @@ class ProfileGistsPresenter extends BasePresenter implemen sendToView(view -> view.onNotifyAdapter(listResponse.getItems(), page)); manageDisposable(Gist.save(Stream.of(listResponse.getItems()).toList(), parameter)); }); + return true; } @NonNull @Override public ArrayList getGists() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/org/members/OrgMembersFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/org/members/OrgMembersFragment.java index 83a73940..027b040f 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/org/members/OrgMembersFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/org/members/OrgMembersFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.UsersAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,6 +31,7 @@ public class OrgMembersFragment extends BaseFragment onLoadMore; private UsersAdapter adapter; @@ -73,6 +75,7 @@ public class OrgMembersFragment extends BaseFragment implements O super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -52,13 +52,14 @@ class OrgMembersPresenter extends BasePresenter implements O setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(OrgMembersMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getOrgService(isEnterprise()).getOrgMembers(parameter, page), response -> { lastPage = response.getLast(); sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getFollowers() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/org/repos/OrgReposFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/org/repos/OrgReposFragment.java index 55475770..84fc2287 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/org/repos/OrgReposFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/org/repos/OrgReposFragment.java @@ -17,6 +17,7 @@ import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.profile.repos.ProfileReposFilterBottomSheetDialog; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -32,6 +33,7 @@ public class OrgReposFragment extends BaseFragment onLoadMore; private ReposAdapter adapter; @@ -75,6 +77,7 @@ public class OrgReposFragment extends BaseFragment implements OrgRe super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -61,7 +61,7 @@ class OrgReposPresenter extends BasePresenter implements OrgRe setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(OrgReposMvp.View::hideProgress); - return; + return false; } filterOptions.setOrg(true); makeRestCall(RestProvider.getOrgService(isEnterprise()).getOrgRepos(parameter, filterOptions.getQueryMap(), page), @@ -72,6 +72,7 @@ class OrgReposPresenter extends BasePresenter implements OrgRe } sendToView(view -> view.onNotifyAdapter(repoModelPageable.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getRepos() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/OrgTeamFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/OrgTeamFragment.java index e5daeea8..e42019b9 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/OrgTeamFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/OrgTeamFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.TeamsAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,6 +31,7 @@ public class OrgTeamFragment extends BaseFragment onLoadMore; private TeamsAdapter adapter; @@ -73,6 +75,7 @@ public class OrgTeamFragment extends BaseFragment implements OrgTeam super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -54,13 +54,14 @@ class OrgTeamPresenter extends BasePresenter implements OrgTeam setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(OrgTeamMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getOrgService(isEnterprise()).getOrgTeams(parameter, page), response -> { lastPage = response.getLast(); sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getTeams() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/members/TeamMembersFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/members/TeamMembersFragment.java index ce8d627e..007ebf3d 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/members/TeamMembersFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/members/TeamMembersFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.UsersAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,6 +31,7 @@ public class TeamMembersFragment extends BaseFragment onLoadMore; private UsersAdapter adapter; @@ -73,6 +75,7 @@ public class TeamMembersFragment extends BaseFragment implements super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable Long parameter) { + @Override public boolean onCallApi(int page, @Nullable Long parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -52,13 +52,14 @@ class TeamMembersPresenter extends BasePresenter implements setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(TeamMembersMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getOrgService(isEnterprise()).getTeamMembers(parameter, page), response -> { lastPage = response.getLast(); sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getFollowers() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/repos/TeamReposFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/repos/TeamReposFragment.java index 9e35ff5f..61d340e3 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/repos/TeamReposFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/org/teams/details/repos/TeamReposFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.ReposAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,6 +31,7 @@ public class TeamReposFragment extends BaseFragment onLoadMore; private ReposAdapter adapter; @@ -73,6 +75,7 @@ public class TeamReposFragment extends BaseFragment implements Tea super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable Long parameter) { + @Override public boolean onCallApi(int page, @Nullable Long parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -52,13 +52,14 @@ class TeamReposPresenter extends BasePresenter implements Tea setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(TeamReposMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getOrgService(isEnterprise()).getTeamRepos(parameter, page), repoModelPageable -> { lastPage = repoModelPageable.getLast(); sendToView(view -> view.onNotifyAdapter(repoModelPageable.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getRepos() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewFragment.java index aa7d6db6..ccd9e760 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewFragment.java @@ -34,13 +34,16 @@ import com.fastaccess.helper.Bundler; import com.fastaccess.helper.InputHelper; import com.fastaccess.helper.ParseDateFormat; import com.fastaccess.provider.emoji.EmojiParser; +import com.fastaccess.provider.scheme.SchemeParser; import com.fastaccess.ui.adapter.ProfileOrgsAdapter; +import com.fastaccess.ui.adapter.ProfilePinnedReposAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.profile.ProfilePagerMvp; import com.fastaccess.ui.widgets.AvatarLayout; import com.fastaccess.ui.widgets.FontTextView; import com.fastaccess.ui.widgets.SpannableBuilder; import com.fastaccess.ui.widgets.contributions.GitHubContributionsView; +import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; import com.fastaccess.ui.widgets.recyclerview.layout_manager.GridManager; @@ -48,6 +51,7 @@ import java.util.List; import butterknife.BindView; import butterknife.OnClick; +import pr.GetPinnedReposQuery; import static android.view.Gravity.TOP; import static android.view.View.GONE; @@ -78,12 +82,15 @@ public class ProfileOverviewFragment extends BaseFragment nodes) { + if (!nodes.isEmpty()) { + pinnedReposTextView.setVisibility(VISIBLE); + pinnedReposCard.setVisibility(VISIBLE); + ProfilePinnedReposAdapter adapter = new ProfilePinnedReposAdapter(nodes); + adapter.setListener(new BaseViewHolder.OnItemClickListener() { + @Override public void onItemClick(int position, View v, GetPinnedReposQuery.Node item) { + SchemeParser.launchUri(getContext(), item.url().toString()); + } + + @Override public void onItemLongClick(int position, View v, GetPinnedReposQuery.Node item) {} + }); + pinnedList.addDivider(); + pinnedList.setAdapter(adapter); + } else { + pinnedReposTextView.setVisibility(GONE); + pinnedReposCard.setVisibility(GONE); + } + } + @Override public void showProgress(@StringRes int resId) { progress.setVisibility(VISIBLE); } @@ -331,5 +359,4 @@ public class ProfileOverviewFragment extends BaseFragment nodes); } interface Presenter extends BaseMvp.FAPresenter { @@ -57,6 +61,8 @@ public interface ProfileOverviewMvp { @NonNull ArrayList getContributions(); + @NonNull ArrayList getNodes(); + @NonNull String getLogin(); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewPresenter.java index 726363e8..fcc43eba 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/overview/ProfileOverviewPresenter.java @@ -6,6 +6,9 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; +import com.apollographql.apollo.ApolloCall; +import com.apollographql.apollo.rx2.Rx2Apollo; +import com.fastaccess.App; import com.fastaccess.data.dao.model.Login; import com.fastaccess.data.dao.model.User; import com.fastaccess.helper.BundleConstant; @@ -21,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import io.reactivex.Observable; +import pr.GetPinnedReposQuery; /** * Created by Kosh on 03 Dec 2016, 9:16 AM @@ -30,7 +34,8 @@ class ProfileOverviewPresenter extends BasePresenter im @com.evernote.android.state.State boolean isSuccessResponse; @com.evernote.android.state.State boolean isFollowing; @com.evernote.android.state.State String login; - @com.evernote.android.state.State ArrayList userOrgs = new ArrayList<>(); + private ArrayList userOrgs = new ArrayList<>(); + private ArrayList nodes = new ArrayList<>(); private ArrayList contributions = new ArrayList<>(); private static final String URL = "https://github.com/users/%s/contributions"; @@ -83,9 +88,12 @@ class ProfileOverviewPresenter extends BasePresenter im } login = bundle.getString(BundleConstant.EXTRA); if (login != null) { - loadOrgs(); -// loadUrlBackgroundImage(); - makeRestCall(RestProvider.getUserService(isEnterprise()).getUser(login), userModel -> { + makeRestCall(RestProvider.getUserService(isEnterprise()) + .getUser(login) + .doOnComplete(() -> { + loadPinnedRepos(login); + loadOrgs(); + }), userModel -> { onSendUserToView(userModel); if (userModel != null) { userModel.save(userModel); @@ -97,6 +105,29 @@ class ProfileOverviewPresenter extends BasePresenter im } } + @SuppressWarnings("ConstantConditions") private void loadPinnedRepos(@NonNull String login) { + ApolloCall apolloCall = App.getInstance().getApolloClient() + .query(GetPinnedReposQuery.builder() + .login(login) + .build()); + manageObservable(Rx2Apollo.from(apolloCall) + .filter(dataResponse -> !dataResponse.hasErrors()) + .flatMap(dataResponse -> { + if (dataResponse.data() != null && dataResponse.data().user() != null) { + return Observable.fromIterable(dataResponse.data().user().pinnedRepositories().edges()); + } + return Observable.empty(); + }) + .map(GetPinnedReposQuery.Edge::node) + .toList() + .toObservable() + .doOnNext(nodes1 -> { + nodes.clear(); + nodes.addAll(nodes1); + sendToView(view -> view.onInitPinnedRepos(nodes)); + })); + } + @Override public void onWorkOffline(@NonNull String login) { User userModel = User.getUser(login); if (userModel == null) { @@ -134,6 +165,10 @@ class ProfileOverviewPresenter extends BasePresenter im return contributions; } + @NonNull @Override public ArrayList getNodes() { + return nodes; + } + @NonNull @Override public String getLogin() { return login; } diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java index aa57253e..c2070ee2 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.ReposAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -31,6 +32,7 @@ public class ProfileReposFragment extends BaseFragment onLoadMore; private ReposAdapter adapter; @@ -74,6 +76,7 @@ public class ProfileReposFragment extends BaseFragment implemen super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (currentLoggedIn == null) { currentLoggedIn = Login.getUser().getLogin(); } @@ -69,7 +69,7 @@ class ProfileReposPresenter extends BasePresenter implemen setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(ProfileReposMvp.View::hideProgress); - return; + return false; } boolean isProfile = TextUtils.equals(currentLoggedIn, username); filterOptions.setIsPersonalProfile(isProfile); @@ -83,6 +83,7 @@ class ProfileReposPresenter extends BasePresenter implemen } sendToView(view -> view.onNotifyAdapter(repoModelPageable.getItems(), page)); }); + return true; } @NonNull @Override public ArrayList getRepos() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/starred/ProfileStarredFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/starred/ProfileStarredFragment.java index 36f0a1e8..39a0541b 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/starred/ProfileStarredFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/starred/ProfileStarredFragment.java @@ -18,6 +18,7 @@ import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.repos.RepoPagerMvp; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -32,6 +33,7 @@ public class ProfileStarredFragment extends BaseFragment onLoadMore; private ReposAdapter adapter; private RepoPagerMvp.TabsBadgeListener tabsBadgeListener; @@ -91,6 +93,7 @@ public class ProfileStarredFragment extends BaseFragment impl super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (parameter == null) { throw new NullPointerException("Username is null"); } @@ -63,7 +63,7 @@ class ProfileStarredPresenter extends BasePresenter impl setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(ProfileStarredMvp.View::hideProgress); - return; + return false; } Observable> observable; if (starredCount == -1) { @@ -87,6 +87,7 @@ class ProfileStarredPresenter extends BasePresenter impl view.onNotifyAdapter(repoModelPageable.getItems(), page); }); }); + return true; } @NonNull @Override public ArrayList getRepos() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerPresenter.java index 39dc54ed..f1961227 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerPresenter.java @@ -39,7 +39,7 @@ class RepoPagerPresenter extends BasePresenter implements Rep if (InputHelper.isEmpty(login) || InputHelper.isEmpty(repoId)) return; makeRestCall(RestProvider.getRepoService(isEnterprise()).getRepo(login(), repoId()), repoModel -> { this.repo = repoModel; - manageObservable(this.repo.save(repo).toObservable()); + manageDisposable(this.repo.save(repo)); updatePinned(repoModel); sendToView(view -> { view.onInitRepo(); diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/RepoCommitsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/RepoCommitsFragment.java index 12be0071..70698d0c 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/RepoCommitsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/RepoCommitsFragment.java @@ -21,6 +21,7 @@ import com.fastaccess.ui.modules.repos.extras.branches.pager.BranchesPagerFragme import com.fastaccess.ui.widgets.FontTextView; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -35,6 +36,7 @@ public class RepoCommitsFragment extends BaseFragment implements super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable Object parameter) { + @Override public boolean onCallApi(int page, @Nullable Object parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); @@ -60,9 +60,9 @@ class RepoCommitsPresenter extends BasePresenter implements setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(RepoCommitsMvp.View::hideProgress); - return; + return false; } - if (repoId == null || login == null) return; + if (repoId == null || login == null) return false; makeRestCall(RestProvider.getRepoService(isEnterprise()).getCommits(login, repoId, branch, page), response -> { if (response != null && response.getItems() != null) { @@ -73,6 +73,7 @@ class RepoCommitsPresenter extends BasePresenter implements } sendToView(view -> view.onNotifyAdapter(response != null ? response.getItems() : null, page)); }); + return true; } @Override public void onFragmentCreated(@NonNull Bundle bundle) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/CommitPagerActivity.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/CommitPagerActivity.java index 1c7c0845..0110f162 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/CommitPagerActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/CommitPagerActivity.java @@ -31,6 +31,7 @@ import com.fastaccess.provider.timeline.HtmlHelper; import com.fastaccess.ui.adapter.FragmentsPagerAdapter; import com.fastaccess.ui.base.BaseActivity; import com.fastaccess.ui.base.BaseFragment; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; import com.fastaccess.ui.modules.repos.RepoPagerActivity; import com.fastaccess.ui.modules.repos.code.commit.details.comments.CommitCommentsFragment; import com.fastaccess.ui.widgets.AvatarLayout; @@ -63,6 +64,7 @@ public class CommitPagerActivity extends BaseActivity toggleMap = new LinkedHashMap<>(); - - private IssuePullsTimelineAdapter adapter; + private CommentEditorFragment.CommentListener commentsCallback; + private IssuesTimelineAdapter adapter; private OnLoadMore onLoadMore; public static CommitCommentsFragment newInstance(@NonNull String login, @NonNull String repoId, @NonNull String sha) { @@ -59,6 +63,23 @@ public class CommitCommentsFragment extends BaseFragment impl this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } if (page > lastPage || lastPage == 0) { sendToView(CommitCommentsMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); makeRestCall(RestProvider.getRepoService(isEnterprise()).getCommitComments(login, repoId, sha, page) - .flatMap(listResponse -> { - lastPage = listResponse.getLast(); - return Observable.just(TimelineModel.construct(listResponse.getItems())); - }), listResponse -> sendToView(view -> view.onNotifyAdapter(listResponse, page))); + .flatMap(listResponse -> { + lastPage = listResponse.getLast(); + return TimelineModel.construct(listResponse.getItems()); + }) + .doOnComplete(() -> { + if (lastPage <= 1) { + sendToView(CommitCommentsMvp.View::showReload); + } + }), + listResponse -> sendToView(view -> view.onNotifyAdapter(listResponse, page))); + return true; } @Override public void onFragmentCreated(@Nullable Bundle bundle) { @@ -103,7 +111,7 @@ class CommitCommentsPresenter extends BasePresenter impl @Override public void onWorkOffline() { if (comments.isEmpty()) { manageDisposable(RxHelper.getObservable(Comment.getCommitComments(repoId(), login(), sha).toObservable()) - .flatMap(comments -> Observable.just(TimelineModel.construct(comments))) + .flatMap(TimelineModel::construct) .subscribe(models -> sendToView(view -> view.onNotifyAdapter(models, 1)))); } else { sendToView(CommitCommentsMvp.View::hideProgress); @@ -130,6 +138,13 @@ class CommitCommentsPresenter extends BasePresenter impl return getReactionsProvider().isCallingApi(id, vId); } + @Override public void onHandleComment(@NonNull String text, @Nullable Bundle bundle) { + CommentRequestModel model = new CommentRequestModel(); + model.setBody(text); + makeRestCall(RestProvider.getRepoService(isEnterprise()).postCommitComment(login, repoId, sha, model), + comment -> sendToView(view -> view.addComment(comment))); + } + @Override public void onItemClick(int position, View v, TimelineModel timelineModel) { if (getView() != null) { Comment item = timelineModel.getComment(); @@ -160,12 +175,17 @@ class CommitCommentsPresenter extends BasePresenter impl } } - @Override public void onItemLongClick(int position, View v, TimelineModel item) { - ReactionTypes reactionTypes = ReactionTypes.get(v.getId()); - if (reactionTypes != null) { - if (getView() != null) getView().showReactionsPopup(reactionTypes, login, repoId, item.getComment().getId()); + @Override public void onItemLongClick(int position, View v, TimelineModel timelineModel) { + if (v.getId() == R.id.commentMenu) { + Comment item = timelineModel.getComment(); + if (getView() != null) getView().onReply(item.getUser(), item.getBody()); } else { - onItemClick(position, v, item); + ReactionTypes reactionTypes = ReactionTypes.get(v.getId()); + if (reactionTypes != null) { + if (getView() != null) getView().showReactionsPopup(reactionTypes, login, repoId, timelineModel.getComment().getId()); + } else { + onItemClick(position, v, timelineModel); + } } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesFragment.java index 120a6767..0b7411a0 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesFragment.java @@ -25,6 +25,7 @@ import com.fastaccess.ui.modules.reviews.AddReviewDialogFragment; import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.ArrayList; import java.util.HashMap; @@ -42,6 +43,7 @@ public class CommitFilesFragment extends BaseFragment toggleMap = new LinkedHashMap<>(); private CommitPagerMvp.View viewCallback; @@ -106,6 +108,7 @@ public class CommitFilesFragment extends BaseFragment implements .map(CommitFileChanges::construct) .doOnSubscribe(disposable -> sendToView(CommitFilesMvp.View::clearAdapter)) .doOnNext(commitFileChanges -> sendToView(view -> view.onNotifyAdapter(commitFileChanges))) - .doFinally(() -> sendToView(BaseMvp.FAView::hideProgress))); + .doOnComplete(() -> sendToView(BaseMvp.FAView::hideProgress))); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesSingleton.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesSingleton.java index 69c79ada..53d2b166 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesSingleton.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/commit/details/files/CommitFilesSingleton.java @@ -25,7 +25,7 @@ class CommitFilesSingleton { private CommitFilesSingleton() {} void putFiles(@NonNull String id, @NonNull CommitFileListModel commitFiles) { - files.clear(); + clear(); files.put(id, commitFiles); } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/contributors/RepoContributorsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/contributors/RepoContributorsFragment.java index 7e7fe853..18f7fbf7 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/contributors/RepoContributorsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/contributors/RepoContributorsFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.UsersAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -30,6 +31,7 @@ public class RepoContributorsFragment extends BaseFragment this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable Object parameter) { + @Override public boolean onCallApi(int page, @Nullable Object parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); @@ -51,7 +51,7 @@ class RepoContributorsPresenter extends BasePresenter setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(RepoContributorsMvp.View::hideProgress); - return; + return false; } makeRestCall(RestProvider.getRepoService(isEnterprise()).getContributors(login, repoId, page), response -> { @@ -60,6 +60,7 @@ class RepoContributorsPresenter extends BasePresenter } sendToView(view -> view.onNotifyAdapter(response != null ? response.getItems() : null, page)); }); + return true; } @Override public void onFragmentCreated(@NonNull Bundle bundle) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/RepoFilesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/RepoFilesFragment.java index c199a44f..c3bdc61f 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/RepoFilesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/RepoFilesFragment.java @@ -28,6 +28,7 @@ import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import butterknife.BindView; @@ -40,6 +41,7 @@ public class RepoFilesFragment extends BaseFragment implements ViewerMvp isMarkdown = fileModel.isMarkdown(); sendToView(view -> { if (isRepo || isMarkdown) { - view.onSetMdText(downloadedStream, fileModel.getFullUrl()); + view.onSetMdText(downloadedStream, fileModel.getFullUrl(), false); } else { view.onSetCode(downloadedStream); } @@ -110,8 +110,8 @@ class ViewerPresenter extends BasePresenter implements ViewerMvp Observable streamObservable = MarkDownProvider.isMarkdown(url) ? RestProvider.getRepoService(isEnterprise()).getFileAsHtmlStream(url) : RestProvider.getRepoService(isEnterprise()).getFileAsStream(url); - makeRestCall(isRepo ? RestProvider.getRepoService(isEnterprise()).getReadmeHtml(url) - : streamObservable, content -> { + Observable observable = isRepo ? RestProvider.getRepoService(isEnterprise()).getReadmeHtml(url) : streamObservable; + makeRestCall(observable, content -> { downloadedStream = content; ViewerFile fileModel = new ViewerFile(); fileModel.setContent(downloadedStream); @@ -121,7 +121,7 @@ class ViewerPresenter extends BasePresenter implements ViewerMvp fileModel.setMarkdown(true); isMarkdown = true; isRepo = true; - sendToView(view -> view.onSetMdText(downloadedStream, htmlUrl == null ? url : htmlUrl)); + sendToView(view -> view.onSetMdText(downloadedStream, htmlUrl == null ? url : htmlUrl, false)); } else { isMarkdown = MarkDownProvider.isMarkdown(url); if (isMarkdown) { @@ -141,7 +141,7 @@ class ViewerPresenter extends BasePresenter implements ViewerMvp fileModel.setMarkdown(true); fileModel.setContent(downloadedStream); manageObservable(fileModel.save(fileModel).toObservable()); - sendToView(view -> view.onSetMdText(downloadedStream, htmlUrl == null ? url : htmlUrl)); + sendToView(view -> view.onSetMdText(downloadedStream, htmlUrl == null ? url : htmlUrl, true)); }); return; } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/releases/RepoReleasesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/releases/RepoReleasesFragment.java index e058d9a3..1cc75247 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/releases/RepoReleasesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/releases/RepoReleasesFragment.java @@ -24,6 +24,7 @@ import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.ListDialogView; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.ArrayList; import java.util.List; @@ -38,6 +39,7 @@ public class RepoReleasesFragment extends BaseFragment implemen super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable Object parameter) { + @Override public boolean onCallApi(int page, @Nullable Object parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); @@ -57,9 +57,9 @@ class RepoReleasesPresenter extends BasePresenter implemen setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(RepoReleasesMvp.View::hideProgress); - return; + return false; } - if (repoId == null || login == null) return; + if (repoId == null || login == null) return false; makeRestCall(RestProvider.getRepoService(isEnterprise()).getReleases(login, repoId, page), response -> { if (response.getItems() == null || response.getItems().isEmpty()) { @@ -68,6 +68,7 @@ class RepoReleasesPresenter extends BasePresenter implemen } onResponse(response); }); + return true; } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/assignees/AssigneesDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/assignees/AssigneesDialogFragment.java index 5f63f19d..c39dab86 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/assignees/AssigneesDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/assignees/AssigneesDialogFragment.java @@ -20,6 +20,7 @@ import com.fastaccess.ui.base.BaseDialogFragment; import com.fastaccess.ui.widgets.FontTextView; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.ArrayList; import java.util.HashMap; @@ -40,6 +41,7 @@ public class AssigneesDialogFragment extends BaseDialogFragment selectionMap; private AssigneesAdapter adapter; @@ -88,6 +90,7 @@ public class AssigneesDialogFragment extends BaseDialogFragment(), BranchesMvp.View { - val recycler: DynamicRecyclerView by lazy { view!!.findViewById(R.id.recycler) } - val refresh: SwipeRefreshLayout by lazy { view!!.findViewById(R.id.refresh) } - val stateLayout: StateLayout by lazy { view!!.findViewById(R.id.stateLayout) } + + @BindView(R.id.recycler) lateinit var recycler: DynamicRecyclerView + @BindView(R.id.refresh) lateinit var refresh: SwipeRefreshLayout + @BindView(R.id.stateLayout) lateinit var stateLayout: StateLayout + @BindView(R.id.fastScroller) lateinit var fastScroller: RecyclerViewFastScroller + private var onLoadMore: OnLoadMore? = null private var branchCallback: BranchesPagerListener? = null - val adapter by lazy { BranchesAdapter(presenter.branches, presenter) } + private val adapter by lazy { BranchesAdapter(presenter.branches, presenter) } override fun onAttach(context: Context) { super.onAttach(context) @@ -72,6 +77,7 @@ class BranchesFragment : BaseFragment(), Br if (savedInstanceState == null) { presenter.onFragmentCreated(arguments) } + fastScroller.attachRecyclerView(recycler) } override fun showProgress(resId: Int) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesPresenter.kt index 85d19469..91e38192 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesPresenter.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesPresenter.kt @@ -68,10 +68,10 @@ class BranchesPresenter : BasePresenter(), BranchesMvp.Present this.previousTotal = previousTotal } - override fun onCallApi(page: Int, parameter: Boolean?) { + override fun onCallApi(page: Int, parameter: Boolean?): Boolean { if (login.isNullOrEmpty() || repoId.isNullOrEmpty()) { sendToView({ it.hideProgress() }) - return + return false } if (page == 1) { lastPage = Integer.MAX_VALUE @@ -79,10 +79,11 @@ class BranchesPresenter : BasePresenter(), BranchesMvp.Present } if (page > lastPage || lastPage == 0) { sendToView({ it.hideProgress() }) - return + return false } currentPage = page callApi(login!!, repoId!!, page) + return true } } \ No newline at end of file diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt index 53044da8..ecf94306 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt @@ -6,6 +6,7 @@ import android.support.design.widget.TabLayout import android.support.v4.view.ViewPager import android.support.v7.widget.Toolbar import android.view.View +import butterknife.BindView import com.fastaccess.R import com.fastaccess.data.dao.BranchesModel import com.fastaccess.data.dao.FragmentPagerAdapterModel @@ -21,9 +22,11 @@ import com.fastaccess.ui.modules.repos.extras.branches.BranchesMvp * Created by kosh on 15/07/2017. */ class BranchesPagerFragment : BaseDialogFragment>(), BranchesPagerListener { - val pager: ViewPager by lazy { view!!.findViewById(R.id.pager) } - val tabs: TabLayout by lazy { view!!.findViewById(R.id.tabs) } - val toolbar: Toolbar by lazy { view!!.findViewById(R.id.toolbar) } + + @BindView(R.id.pager) lateinit var pager: ViewPager + @BindView(R.id.tabs) lateinit var tabs: TabLayout + @BindView(R.id.toolbar) lateinit var toolbar: Toolbar + private var branchCallback: BranchesMvp.BranchSelectionListener? = null override fun onAttach(context: Context) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsDialogFragment.java index 2db81cce..7122730b 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsDialogFragment.java @@ -2,14 +2,12 @@ package com.fastaccess.ui.modules.repos.extras.labels; import android.content.Context; import android.os.Bundle; -import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.StringRes; import android.support.v4.widget.SwipeRefreshLayout; import android.view.View; -import com.annimon.stream.Collectors; -import com.annimon.stream.Stream; import com.evernote.android.state.State; import com.fastaccess.R; import com.fastaccess.data.dao.LabelListModel; @@ -17,18 +15,17 @@ import com.fastaccess.data.dao.LabelModel; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; import com.fastaccess.helper.InputHelper; +import com.fastaccess.provider.rest.loadmore.OnLoadMore; import com.fastaccess.ui.adapter.LabelsAdapter; import com.fastaccess.ui.base.BaseDialogFragment; import com.fastaccess.ui.modules.repos.extras.labels.create.CreateLabelDialogFragment; import com.fastaccess.ui.widgets.FontTextView; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import butterknife.BindView; import butterknife.OnClick; @@ -44,15 +41,16 @@ public class LabelsDialogFragment extends BaseDialogFragment selectionMap; + @BindView(R.id.fastScroller) RecyclerViewFastScroller fastScroller; + @State ArrayList labelModels = new ArrayList<>(); + + private OnLoadMore onLoadMore; private LabelsAdapter adapter; private LabelsMvp.SelectedLabelsListener callback; - public static LabelsDialogFragment newInstance(@NonNull List models, @Nullable LabelListModel selectedLabels, - @NonNull String repo, @NonNull String login) { + public static LabelsDialogFragment newInstance(@Nullable LabelListModel selectedLabels, @NonNull String repo, @NonNull String login) { LabelsDialogFragment fragment = new LabelsDialogFragment(); fragment.setArguments(Bundler.start() - .putParcelableArrayList(BundleConstant.ITEM, (ArrayList) models) .putParcelableArrayList(BundleConstant.EXTRA, selectedLabels) .put(BundleConstant.EXTRA_TWO, repo) .put(BundleConstant.EXTRA_THREE, login) @@ -89,45 +87,65 @@ public class LabelsDialogFragment extends BaseDialogFragment getPresenter().onCallApi(1, null)); + stateLayout.setOnReloadListener(v -> getPresenter().onCallApi(1, null)); recycler.addDivider(); title.setText(R.string.labels); add.setVisibility(View.VISIBLE); - List list = getArguments().getParcelableArrayList(BundleConstant.ITEM); - List selectedLabels = getArguments().getParcelableArrayList(BundleConstant.EXTRA); - if (list != null) { - adapter = new LabelsAdapter(list, this); - recycler.setAdapter(adapter); - if (savedInstanceState == null) { - if (selectedLabels != null && !selectedLabels.isEmpty()) { - Stream.of(selectedLabels) - .map(list::indexOf) - .filter(value -> value != -1) - .forEach(integer -> onToggleSelection(integer, true)); - } - } + labelModels = getArguments().getParcelableArrayList(BundleConstant.EXTRA); + if (labelModels == null) { + labelModels = new ArrayList<>(); + } + adapter = new LabelsAdapter(getPresenter().getLabels(), this); + recycler.setAdapter(adapter); + fastScroller.attachRecyclerView(recycler); + recycler.addOnScrollListener(getLoadMore()); + if (getPresenter().getLabels().isEmpty() && !getPresenter().isApiCalled()) { + getPresenter().onCallApi(1, null); } } @NonNull @Override public LabelsPresenter providePresenter() { - return new LabelsPresenter(); + Bundle bundle = getArguments(); + //noinspection ConstantConditions + return new LabelsPresenter(bundle.getString(BundleConstant.EXTRA_THREE), bundle.getString(BundleConstant.EXTRA_TWO)); } - @Override public boolean isLabelSelected(int position) { - return getSelectionMap().get(position) != null; + @Override public boolean isLabelSelected(LabelModel labelModel) { + return labelModels.indexOf(labelModel) != -1; } - @Override public void onToggleSelection(int position, boolean select) { + @Override public void onToggleSelection(LabelModel labelModel, boolean select) { if (select) { - getSelectionMap().put(position, adapter.getItem(position)); + labelModels.add(labelModel); } else { - getSelectionMap().remove(position); + labelModels.remove(labelModel); } adapter.notifyDataSetChanged(); } + @SuppressWarnings("unchecked") @NonNull @Override public OnLoadMore getLoadMore() { + if (onLoadMore == null) { + onLoadMore = new OnLoadMore(getPresenter()); + } + return onLoadMore; + } + + @Override public void onNotifyAdapter(@Nullable List items, int page) { + hideProgress(); + if (items == null || items.isEmpty()) { + adapter.clear(); + return; + } + if (page <= 1) { + adapter.insertItems(items); + } else { + adapter.addItems(items); + } + } + @Override public void onLabelAdded(@NonNull LabelModel labelModel) { adapter.addItem(labelModel, 0); recycler.scrollToPosition(0); @@ -139,22 +157,34 @@ public class LabelsDialogFragment extends BaseDialogFragment labels = Stream.of(selectionMap) - .filter(value -> value.getValue() != null) - .map(Map.Entry::getValue) - .collect(Collectors.toCollection(ArrayList::new)); - if (labels != null && !labels.isEmpty()) { - callback.onSelectedLabels(labels); - } + callback.onSelectedLabels(labelModels); dismiss(); break; } } - public HashMap getSelectionMap() { - if (selectionMap == null) { - selectionMap = new LinkedHashMap<>(); - } - return selectionMap; + @Override public void showProgress(@StringRes int resId) { + refresh.setRefreshing(true); + stateLayout.showProgress(); + } + + @Override public void hideProgress() { + refresh.setRefreshing(false); + stateLayout.hideProgress(); + } + + @Override public void showErrorMessage(@NonNull String message) { + showReload(); + super.showErrorMessage(message); + } + + @Override public void showMessage(int titleRes, int msgRes) { + showReload(); + super.showMessage(titleRes, msgRes); + } + + private void showReload() { + hideProgress(); + stateLayout.showReload(adapter.getItemCount()); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsMvp.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsMvp.java index 049e98b4..302fb453 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsMvp.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsMvp.java @@ -1,12 +1,15 @@ package com.fastaccess.ui.modules.repos.extras.labels; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.fastaccess.data.dao.LabelModel; +import com.fastaccess.provider.rest.loadmore.OnLoadMore; import com.fastaccess.ui.adapter.LabelsAdapter; import com.fastaccess.ui.base.mvp.BaseMvp; import java.util.ArrayList; +import java.util.List; /** * Created by Kosh on 22 Feb 2017, 7:22 PM @@ -19,8 +22,17 @@ public interface LabelsMvp { } interface View extends BaseMvp.FAView, LabelsAdapter.OnSelectLabel { + + @NonNull OnLoadMore getLoadMore(); + + void onNotifyAdapter(@Nullable List items, int page); + void onLabelAdded(@NonNull LabelModel labelModel); } - interface Presenter {} + interface Presenter extends BaseMvp.PaginationListener { + + @NonNull ArrayList getLabels(); + + } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsPresenter.java index 7e94210c..ab45ed71 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/LabelsPresenter.java @@ -1,9 +1,66 @@ package com.fastaccess.ui.modules.repos.extras.labels; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.fastaccess.data.dao.LabelModel; +import com.fastaccess.provider.rest.RestProvider; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; +import java.util.ArrayList; + /** * Created by Kosh on 22 Feb 2017, 7:23 PM */ -class LabelsPresenter extends BasePresenter implements LabelsMvp.Presenter {} +class LabelsPresenter extends BasePresenter implements LabelsMvp.Presenter { + + private int page; + private int previousTotal; + private int lastPage = Integer.MAX_VALUE; + private ArrayList labels = new ArrayList<>(); + @com.evernote.android.state.State String login; + @com.evernote.android.state.State String repoId; + + LabelsPresenter(@NonNull String login, @NonNull String repoId) { + this.login = login; + this.repoId = repoId; + } + + @NonNull @Override public ArrayList getLabels() { + return labels; + } + + @Override public int getCurrentPage() { + return page; + } + + @Override public int getPreviousTotal() { + return previousTotal; + } + + @Override public void setCurrentPage(int page) { + this.page = page; + } + + @Override public void setPreviousTotal(int previousTotal) { + this.previousTotal = previousTotal; + } + + @Override public boolean onCallApi(int page, @Nullable Object parameter) { + if (page == 1) { + lastPage = Integer.MAX_VALUE; + sendToView(view -> view.getLoadMore().reset()); + } + if (page > lastPage || lastPage == 0) { + sendToView(LabelsMvp.View::hideProgress); + return false; + } + setCurrentPage(page); + makeRestCall(RestProvider.getRepoService(isEnterprise()).getLabels(login, repoId, page), response -> { + lastPage = response.getLast(); + sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); + }); + return true; + } +} diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/create/CreateLabelDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/create/CreateLabelDialogFragment.java index f3d1d64f..c5ea19d6 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/create/CreateLabelDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/labels/create/CreateLabelDialogFragment.java @@ -17,6 +17,7 @@ import com.fastaccess.ui.adapter.LabelColorsAdapter; import com.fastaccess.ui.base.BaseDialogFragment; import com.fastaccess.ui.modules.repos.extras.labels.LabelsMvp; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.Arrays; @@ -32,6 +33,7 @@ public class CreateLabelDialogFragment extends BaseDialogFragment(R.id.stateLayout) } - - val loader: ProgressBar by lazy { view!!.findViewById(R.id.readmeLoader) } - val webView: PrettifyWebView by lazy { view!!.findViewById(R.id.webView) } - val licenseName: TextView by lazy { view!!.findViewById(R.id.licenseName) } + @BindView(R.id.stateLayout) lateinit var stateLayout: StateLayout + @BindView(R.id.readmeLoader) lateinit var loader: ProgressBar + @BindView(R.id.webView) lateinit var webView: PrettifyWebView + @BindView(R.id.licenseName) lateinit var licenseName: TextView override fun providePresenter(): RepoLicensePresenter = RepoLicensePresenter() @@ -37,7 +37,7 @@ class RepoLicenseBottomSheet : BaseMvpBottomSheetDialogFragment", "
")
-            webView.setGithubContent("
$licenseText
", null) + webView.setGithubContent("
$licenseText
", null, false) } else { hideProgress() } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/license/RepoLicensePresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/license/RepoLicensePresenter.kt index d7d6ff57..4db1f0ff 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/license/RepoLicensePresenter.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/license/RepoLicensePresenter.kt @@ -9,7 +9,7 @@ import com.fastaccess.ui.base.mvp.presenter.BasePresenter class RepoLicensePresenter : BasePresenter(), RepoLicenseMvp.Presenter { override fun onLoadLicense(login: String, repo: String) { - makeRestCall(RestProvider.getRepoService(isEnterprise()).getLicense(login, repo), + makeRestCall(RestProvider.getRepoService(isEnterprise).getLicense(login, repo), { license -> sendToView { it.onLicenseLoaded(license) } }) } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/MilestoneDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/MilestoneDialogFragment.java index 4b157393..8c76b882 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/MilestoneDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/MilestoneDialogFragment.java @@ -21,6 +21,7 @@ import com.fastaccess.ui.modules.repos.extras.milestone.create.CreateMilestoneDi import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -38,6 +39,7 @@ public class MilestoneDialogFragment extends BaseFragment getPresenter().onLoadMilestones(login, repo)); refresh.setOnRefreshListener(() -> getPresenter().onLoadMilestones(login, repo)); + fastScroller.attachRecyclerView(recycler); } @Override public void showProgress(@StringRes int resId) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/misc/RepoMiscDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/misc/RepoMiscDialogFragment.java index 9639459c..477cf3e8 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/misc/RepoMiscDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/misc/RepoMiscDialogFragment.java @@ -18,6 +18,7 @@ import com.fastaccess.ui.adapter.UsersAdapter; import com.fastaccess.ui.base.BaseDialogFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -32,6 +33,7 @@ public class RepoMiscDialogFragment extends BaseDialogFragment onLoadMore; private UsersAdapter adapter; @@ -100,11 +102,12 @@ public class RepoMiscDialogFragment extends BaseDialogFragment implement this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @RepoMiscMVp.MiscType @Nullable Integer parameter) { + @Override public boolean onCallApi(int page, @RepoMiscMVp.MiscType @Nullable Integer parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); @@ -74,15 +74,15 @@ public class RepoMiscPresenter extends BasePresenter implement setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(RepoMiscMVp.View::hideProgress); - return; + return false; } switch (type) { case RepoMiscMVp.WATCHERS: makeRestCall(RestProvider.getRepoService(isEnterprise()).getWatchers(owner, repo, page), response -> onResponse(page, response)); - break; + return true; case RepoMiscMVp.STARS: makeRestCall(RestProvider.getRepoService(isEnterprise()).getStargazers(owner, repo, page), response -> onResponse(page, response)); - break; + return true; case RepoMiscMVp.FORKS: makeRestCall(RestProvider.getRepoService(isEnterprise()).getForks(owner, repo, page) .flatMap(repoPageable -> { @@ -92,8 +92,9 @@ public class RepoMiscPresenter extends BasePresenter implement .toList() .toObservable(); }), owners -> sendToView(view -> view.onNotifyAdapter(owners, page))); - break; + return true; } + return false; } private void onResponse(int page, @Nullable Pageable response) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/popup/IssuePopupPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/popup/IssuePopupPresenter.java index 906b82da..7aa24dab 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/popup/IssuePopupPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/popup/IssuePopupPresenter.java @@ -16,7 +16,7 @@ public class IssuePopupPresenter extends BasePresenter imple CommentRequestModel requestModel = new CommentRequestModel(); requestModel.setBody(text); makeRestCall(RestProvider.getIssueService(isEnterprise()).createIssueComment(login, repoId, issueNumber, requestModel), - comment -> sendToView(view -> view.onSuccessfullySubmitted())); + comment -> sendToView(IssuePopupMvp.View::onSuccessfullySubmitted)); } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java index b98cd354..75f5de0d 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java @@ -285,7 +285,7 @@ public class CreateIssueActivity extends BaseActivity onLoadMore; private IssuesAdapter adapter; private RepoPagerMvp.TabsBadgeListener tabsBadgeListener; @@ -108,6 +110,7 @@ public class RepoClosedIssuesFragment extends BaseFragment implements R super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable IssueState parameter) { + @Override public boolean onCallApi(int page, @Nullable IssueState parameter) { if (parameter == null) { sendToView(RepoIssuesMvp.View::hideProgress); - return; + return false; } this.issueState = parameter; if (page == 1) { @@ -69,7 +69,7 @@ class RepoIssuesPresenter extends BasePresenter implements R } if (page > lastPage || lastPage == 0) { sendToView(RepoIssuesMvp.View::hideProgress); - return; + return false; } String sortBy = "created"; if (isLastUpdated) { @@ -87,6 +87,7 @@ class RepoIssuesPresenter extends BasePresenter implements R } sendToView(view -> view.onNotifyAdapter(filtered, page)); }); + return true; } private void onCallCountApi(@NonNull IssueState issueState) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/RepoOpenedIssuesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/RepoOpenedIssuesFragment.java index 719f2e8d..9de1e247 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/RepoOpenedIssuesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/RepoOpenedIssuesFragment.java @@ -27,6 +27,7 @@ import com.fastaccess.ui.modules.repos.issues.create.CreateIssueActivity; import com.fastaccess.ui.modules.repos.issues.issue.details.IssuePagerActivity; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -40,6 +41,7 @@ public class RepoOpenedIssuesFragment extends BaseFragment onLoadMore; private IssuesAdapter adapter; private RepoIssuesPagerMvp.View pagerCallback; @@ -110,6 +112,7 @@ public class RepoOpenedIssuesFragment extends BaseFragment items) { - hideProgress(); - LabelsDialogFragment.newInstance(items, getPresenter().getIssue() != null ? getPresenter().getIssue().getLabels() : null, - getPresenter().getRepoId(), getPresenter().getLogin()) - .show(getSupportFragmentManager(), "LabelsDialogFragment"); - } - @Override public void onUpdateTimeline() { if (pager == null || pager.getAdapter() == null) return; IssueTimelineFragment issueDetailsView = (IssueTimelineFragment) pager.getAdapter().instantiateItem(pager, 0); @@ -374,12 +361,27 @@ public class IssuePagerActivity extends BaseActivity { + AssigneesMvp.SelectedAssigneesListener, IssuePrCallback, + CommentEditorFragment.CommentListener { void onSetupIssue(boolean isUpdate); void showSuccessIssueActionMsg(boolean isClose); void showErrorIssueActionMsg(boolean isClose); - void onLabelsRetrieved(@NonNull List items); - void onUpdateTimeline(); void onUpdateMenu(); @@ -66,8 +65,6 @@ public interface IssuePagerMvp { void onLockUnlockIssue(); - void onLoadLabels(); - void onPutMilestones(@NonNull MilestoneModel milestone); void onPutLabels(@NonNull ArrayList labels); @@ -86,5 +83,4 @@ public interface IssuePagerMvp { interface IssuePrCallback { @Nullable T getData(); } - } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/IssuePagerPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/IssuePagerPresenter.java index 7e6254e5..290cc749 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/IssuePagerPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/IssuePagerPresenter.java @@ -142,16 +142,15 @@ class IssuePagerPresenter extends BasePresenter implements I manageDisposable(RxHelper.getObservable(RestProvider.getIssueService(isEnterprise()).editIssue(login, repoId, issueNumber, requestModel)) .doOnSubscribe(disposable -> sendToView(view -> view.showProgress(0))) - .doOnNext(issue -> { + .subscribe(issue -> { if (issue != null) { sendToView(view -> view.showSuccessIssueActionMsg(currentIssue.getState() == IssueState.open)); issue.setRepoId(issueModel.getRepoId()); issue.setLogin(issueModel.getLogin()); issueModel = issue; - sendToView(view -> view.onSetupIssue(true)); + sendToView(view -> view.onSetupIssue(false)); } - }) - .subscribe(issue -> {/**/}, this::onError)); + }, this::onError)); } } @@ -175,23 +174,6 @@ class IssuePagerPresenter extends BasePresenter implements I } - @Override public void onLoadLabels() { - manageDisposable( - RxHelper.getObservable(RestProvider.getRepoService(isEnterprise()).getLabels(login, repoId)) - .doOnSubscribe(disposable -> onSubscribed(false)) - .doOnNext(response -> { - if (response.getItems() != null && !response.getItems().isEmpty()) { - sendToView(view -> view.onLabelsRetrieved(response.getItems())); - } else { - sendToView(view -> view.showMessage(R.string.error, R.string.no_labels)); - } - }) - .subscribe(labelModelPageable -> {/**/}, throwable -> { - sendToView(view -> view.showMessage(R.string.error, R.string.no_labels)); - }) - ); - } - @Override public void onPutMilestones(@NonNull MilestoneModel milestone) { issueModel.setMilestone(milestone); IssueRequestModel issueRequestModel = IssueRequestModel.clone(issueModel, false); diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelineFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelineFragment.java index 617129f6..3502822b 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelineFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelineFragment.java @@ -19,20 +19,22 @@ import com.fastaccess.data.dao.types.ReactionTypes; import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; +import com.fastaccess.helper.Logger; import com.fastaccess.provider.rest.loadmore.OnLoadMore; import com.fastaccess.provider.timeline.CommentsHelper; import com.fastaccess.provider.timeline.ReactionsProvider; -import com.fastaccess.ui.adapter.IssuePullsTimelineAdapter; +import com.fastaccess.ui.adapter.IssuesTimelineAdapter; import com.fastaccess.ui.adapter.viewholder.TimelineCommentsViewHolder; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.editor.EditorActivity; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; import com.fastaccess.ui.modules.repos.issues.issue.details.IssuePagerMvp; import com.fastaccess.ui.modules.repos.reactions.ReactionsDialogFragment; import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; -import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerFastScroller; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.HashMap; import java.util.LinkedHashMap; @@ -48,12 +50,13 @@ public class IssueTimelineFragment extends BaseFragment toggleMap = new LinkedHashMap<>(); - private IssuePullsTimelineAdapter adapter; + private IssuesTimelineAdapter adapter; private OnLoadMore onLoadMore; private IssuePagerMvp.IssuePrCallback issueCallback; + private CommentEditorFragment.CommentListener commentsCallback; @NonNull public static IssueTimelineFragment newInstance() { return new IssueTimelineFragment(); @@ -66,13 +69,22 @@ public class IssueTimelineFragment extends BaseFragment getLoadMore() { @@ -101,7 +114,7 @@ public class IssueTimelineFragment extends BaseFragment, @@ -69,5 +73,7 @@ public interface IssueTimelineMvp { void onHandleReaction(@IdRes int viewId, long id, @ReactionsProvider.ReactionType int reactionType); boolean isCallingApi(long id, int vId); + + void onHandleComment(@NonNull String text, @Nullable Bundle bundle); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelinePresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelinePresenter.java index 3f8a805b..f907237b 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelinePresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/timeline/IssueTimelinePresenter.java @@ -9,11 +9,13 @@ import android.view.View; import android.widget.PopupMenu; import com.fastaccess.R; +import com.fastaccess.data.dao.CommentRequestModel; import com.fastaccess.data.dao.TimelineModel; import com.fastaccess.data.dao.model.Comment; import com.fastaccess.data.dao.model.Issue; -import com.fastaccess.data.dao.model.IssueEvent; import com.fastaccess.data.dao.model.Login; +import com.fastaccess.data.dao.timeline.GenericEvent; +import com.fastaccess.data.dao.timeline.SourceModel; import com.fastaccess.data.dao.types.ReactionTypes; import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; @@ -22,8 +24,10 @@ import com.fastaccess.provider.rest.RestProvider; import com.fastaccess.provider.scheme.SchemeParser; import com.fastaccess.provider.timeline.CommentsHelper; import com.fastaccess.provider.timeline.ReactionsProvider; +import com.fastaccess.provider.timeline.TimelineConverter; import com.fastaccess.ui.base.mvp.BaseMvp; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; +import com.fastaccess.ui.modules.filter.issues.FilterIssuesActivity; import com.fastaccess.ui.modules.repos.issues.create.CreateIssueActivity; import java.util.ArrayList; @@ -49,9 +53,9 @@ import lombok.Getter; @Override public void onItemClick(int position, View v, TimelineModel item) { if (getView() != null) { + Issue issue = getView().getIssue(); + if (issue == null) return; if (item.getType() == TimelineModel.COMMENT) { - if (getView().getIssue() == null) return; - Issue issue = getView().getIssue(); if (v.getId() == R.id.commentMenu) { PopupMenu popupMenu = new PopupMenu(v.getContext(), v); popupMenu.inflate(R.menu.comments_menu); @@ -77,9 +81,31 @@ import lombok.Getter; onHandleReaction(v.getId(), item.getComment().getId(), ReactionsProvider.COMMENT); } } else if (item.getType() == TimelineModel.EVENT) { - IssueEvent issueEventModel = item.getEvent(); + GenericEvent issueEventModel = item.getGenericEvent(); if (issueEventModel.getCommitUrl() != null) { SchemeParser.launchUri(v.getContext(), Uri.parse(issueEventModel.getCommitUrl())); + } else if (issueEventModel.getLabel() != null) { + FilterIssuesActivity.startActivity(v, issue.getLogin(), issue.getRepoId(), true, + true, isEnterprise(), "label:\"" + issueEventModel.getLabel().getName() + "\""); + } else if (issueEventModel.getMilestone() != null) { + FilterIssuesActivity.startActivity(v, issue.getLogin(), issue.getRepoId(), true, + true, isEnterprise(), "milestone:\"" + issueEventModel.getMilestone().getTitle() + "\""); + } else if (issueEventModel.getAssignee() != null) { + FilterIssuesActivity.startActivity(v, issue.getLogin(), issue.getRepoId(), true, + true, isEnterprise(), "assignee:\"" + issueEventModel.getAssignee().getLogin() + "\""); + } else { + SourceModel sourceModel = issueEventModel.getSource(); + if (sourceModel != null) { + if (sourceModel.getCommit() != null) { + SchemeParser.launchUri(v.getContext(), Uri.parse(sourceModel.getCommit().getUrl())); + } else if (sourceModel.getIssue() != null) { + SchemeParser.launchUri(v.getContext(), Uri.parse(sourceModel.getIssue().getUrl())); + } else if (sourceModel.getPullRequest() != null) { + SchemeParser.launchUri(v.getContext(), Uri.parse(sourceModel.getPullRequest().getUrl())); + } else if (sourceModel.getRepository() != null) { + SchemeParser.launchUri(v.getContext(), Uri.parse(sourceModel.getRepository().getUrl())); + } + } } } else if (item.getType() == TimelineModel.HEADER) { if (v.getId() == R.id.commentMenu) { @@ -113,20 +139,25 @@ import lombok.Getter; @Override public void onItemLongClick(int position, View v, TimelineModel item) { if (getView() == null) return; if (item.getType() == TimelineModel.COMMENT || item.getType() == TimelineModel.HEADER) { - if (getView().getIssue() == null) return; - Issue issue = getView().getIssue(); - String login = issue.getLogin(); - String repoId = issue.getRepoId(); - if (!InputHelper.isEmpty(login) && !InputHelper.isEmpty(repoId)) { - ReactionTypes type = ReactionTypes.get(v.getId()); - if (type != null) { - if (item.getType() == TimelineModel.HEADER) { - getView().showReactionsPopup(type, login, repoId, item.getIssue().getNumber(), true); + if (v.getId() == R.id.commentMenu && item.getType() == TimelineModel.COMMENT) { + Comment comment = item.getComment(); + if (getView() != null) getView().onReply(comment.getUser(), comment.getBody()); + } else { + if (getView().getIssue() == null) return; + Issue issue = getView().getIssue(); + String login = issue.getLogin(); + String repoId = issue.getRepoId(); + if (!InputHelper.isEmpty(login) && !InputHelper.isEmpty(repoId)) { + ReactionTypes type = ReactionTypes.get(v.getId()); + if (type != null) { + if (item.getType() == TimelineModel.HEADER) { + getView().showReactionsPopup(type, login, repoId, item.getIssue().getNumber(), true); + } else { + getView().showReactionsPopup(type, login, repoId, item.getComment().getId(), false); + } } else { - getView().showReactionsPopup(type, login, repoId, item.getComment().getId(), false); + onItemClick(position, v, item); } - } else { - onItemClick(position, v, item); } } } else { @@ -175,6 +206,20 @@ import lombok.Getter; return getReactionsProvider().isCallingApi(id, vId); } + @Override public void onHandleComment(@NonNull String text, @Nullable Bundle bundle) { + if (getView() == null) return; + Issue issue = getView().getIssue(); + if (issue != null) { + if (bundle == null) { + CommentRequestModel commentRequestModel = new CommentRequestModel(); + commentRequestModel.setBody(text); + makeRestCall(RestProvider.getIssueService(isEnterprise()).createIssueComment(issue.getLogin(), issue.getRepoId(), + issue.getNumber(), commentRequestModel), + comment -> sendToView(view -> view.addNewComment(TimelineModel.constructComment(comment)))); + } + } + } + @NonNull private ReactionsProvider getReactionsProvider() { if (reactionsProvider == null) { reactionsProvider = new ReactionsProvider(); @@ -198,10 +243,10 @@ import lombok.Getter; this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable Issue parameter) { + @Override public boolean onCallApi(int page, @Nullable Issue parameter) { if (parameter == null) { sendToView(BaseMvp.FAView::hideProgress); - return; + return false; } if (page == 1) { lastPage = Integer.MAX_VALUE; @@ -209,28 +254,23 @@ import lombok.Getter; } if (page > lastPage || lastPage == 0) { sendToView(IssueTimelineMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); String login = parameter.getLogin(); String repoId = parameter.getRepoId(); int number = parameter.getNumber(); - Observable> observable; - if (page > 1) { - observable = RestProvider.getIssueService(isEnterprise()).getIssueComments(login, repoId, number, page) - .map(comments -> { - lastPage = comments != null ? comments.getLast() : 0; - return TimelineModel.construct(comments != null ? comments.getItems() : null); - }); - } else { - observable = Observable.zip(RestProvider.getIssueService(isEnterprise()).getTimeline(login, repoId, number), - RestProvider.getIssueService(isEnterprise()).getIssueComments(login, repoId, number, page), - (issueEventPageable, commentPageable) -> { - lastPage = commentPageable != null ? commentPageable.getLast() : 0; - return TimelineModel.construct(commentPageable != null ? commentPageable.getItems() : null, - issueEventPageable != null ? issueEventPageable.getItems() : null); - }); - } - makeRestCall(observable, models -> sendToView(view -> view.onNotifyAdapter(models, page))); + Observable> observable = RestProvider.getIssueService(isEnterprise()) + .getTimeline(login, repoId, number, page) + .flatMap(response -> { + if (response != null) { + lastPage = response.getLast(); + } + return TimelineConverter.INSTANCE.convert(response != null ? response.getItems() : null); + }) + .toList() + .toObservable(); + makeRestCall(observable, timeline -> sendToView(view -> view.onNotifyAdapter(timeline, page))); + return true; } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/RepoPullRequestFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/RepoPullRequestFragment.java index 2b25e1f8..1699c02a 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/RepoPullRequestFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/RepoPullRequestFragment.java @@ -24,6 +24,7 @@ import com.fastaccess.ui.modules.repos.extras.popup.IssuePopupFragment; import com.fastaccess.ui.modules.repos.pull_requests.pull_request.details.PullRequestPagerActivity; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -37,6 +38,7 @@ public class RepoPullRequestFragment extends BaseFragment onLoadMore; private PullRequestAdapter adapter; private RepoPagerMvp.TabsBadgeListener tabsBadgeListener; @@ -102,6 +104,7 @@ public class RepoPullRequestFragment extends BaseFragment im super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable IssueState parameter) { + @Override public boolean onCallApi(int page, @Nullable IssueState parameter) { if (parameter == null) { sendToView(RepoPullRequestMvp.View::hideProgress); - return; + return false; } this.issueState = parameter; if (page == 1) { @@ -67,9 +67,9 @@ class RepoPullRequestPresenter extends BasePresenter im setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(RepoPullRequestMvp.View::hideProgress); - return; + return false; } - if (repoId == null || login == null) return; + if (repoId == null || login == null) return false; makeRestCall(RestProvider.getPullRequestService(isEnterprise()).getPullRequests(login, repoId, parameter.name(), page), response -> { lastPage = response.getLast(); if (getCurrentPage() == 1) { @@ -77,6 +77,7 @@ class RepoPullRequestPresenter extends BasePresenter im } sendToView(view -> view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @Override public void onFragmentCreated(@NonNull Bundle bundle) { @@ -123,6 +124,6 @@ class RepoPullRequestPresenter extends BasePresenter im } @Override public void onItemLongClick(int position, View v, PullRequest item) { - if(getView()!=null)getView().onShowPullRequestPopup(item); + if (getView() != null) getView().onShowPullRequestPopup(item); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerActivity.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerActivity.java index 2406fbe3..c31263d3 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerActivity.java @@ -36,6 +36,7 @@ import com.fastaccess.provider.scheme.LinkParserHelper; import com.fastaccess.ui.adapter.FragmentsPagerAdapter; import com.fastaccess.ui.base.BaseActivity; import com.fastaccess.ui.base.BaseFragment; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; import com.fastaccess.ui.modules.main.premium.PremiumActivity; import com.fastaccess.ui.modules.repos.RepoPagerActivity; import com.fastaccess.ui.modules.repos.RepoPagerMvp; @@ -54,7 +55,6 @@ import com.fastaccess.ui.widgets.ViewPagerView; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import java.util.ArrayList; -import java.util.List; import butterknife.BindView; import butterknife.OnClick; @@ -80,6 +80,7 @@ public class PullRequestPagerActivity extends BaseActivity items) { - hideProgress(); - LabelsDialogFragment.newInstance(items, getPresenter().getPullRequest() != null ? getPresenter().getPullRequest().getLabels() : null, - getPresenter().getRepoId(), getPresenter().getLogin()) - .show(getSupportFragmentManager(), "LabelsDialogFragment"); - } - @Override public void onSelectedLabels(@NonNull ArrayList labels) { getPresenter().onPutLabels(labels); } @@ -435,6 +425,23 @@ public class PullRequestPagerActivity extends BaseActivity, PullRequestFilesMvp.PatchCallback { + IssuePagerMvp.IssuePrCallback, PullRequestFilesMvp.PatchCallback, + CommentEditorFragment.CommentListener { void onSetupIssue(boolean update); - void onLabelsRetrieved(@NonNull List items); - void showSuccessIssueActionMsg(boolean isClose); void showErrorIssueActionMsg(boolean isClose); @@ -74,8 +73,6 @@ public interface PullRequestPagerMvp { void onMerge(String s, String msg); - void onLoadLabels(); - void onPutLabels(@NonNull ArrayList labels); void onPutMilestones(@NonNull MilestoneModel milestone); diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerPresenter.java index 70c19554..5b63ce40 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/PullRequestPagerPresenter.java @@ -168,20 +168,6 @@ class PullRequestPagerPresenter extends BasePresenter return PullRequest.getMergeBy(pullRequest, context, false); } - @Override public void onLoadLabels() { - manageDisposable( - RxHelper.getObservable(RestProvider.getRepoService(isEnterprise()).getLabels(login, repoId)) - .doOnSubscribe(disposable -> onSubscribed(false)) - .subscribe(response -> { - if (response.getItems() != null && !response.getItems().isEmpty()) { - sendToView(view -> view.onLabelsRetrieved(response.getItems())); - } else { - sendToView(view -> view.showMessage(R.string.error, R.string.no_labels)); - } - }, throwable -> sendToView(view -> view.showMessage(R.string.error, R.string.no_labels))) - ); - } - @Override public void onPutLabels(@NonNull ArrayList labels) { makeRestCall(RestProvider.getIssueService(isEnterprise()).putLabels(login, repoId, issueNumber, Stream.of(labels).filter(value -> value != null && value.getName() != null) diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/commits/PullRequestCommitsFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/commits/PullRequestCommitsFragment.java index a6d0b728..a8dd48f7 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/commits/PullRequestCommitsFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/commits/PullRequestCommitsFragment.java @@ -16,6 +16,7 @@ import com.fastaccess.ui.adapter.CommitsAdapter; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -31,6 +32,7 @@ public class PullRequestCommitsFragment extends BaseFragment view.getLoadMore().reset()); @@ -58,9 +58,9 @@ class PullRequestCommitsPresenter extends BasePresenter lastPage || lastPage == 0) { sendToView(PullRequestCommitsMvp.View::hideProgress); - return; + return false; } - if (repoId == null || login == null) return; + if (repoId == null || login == null) return false; makeRestCall(RestProvider.getPullRequestService(isEnterprise()).getPullRequestCommits(login, repoId, number, page), response -> { lastPage = response.getLast(); @@ -69,6 +69,7 @@ class PullRequestCommitsPresenter extends BasePresenter view.onNotifyAdapter(response.getItems(), page)); }); + return true; } @Override public void onFragmentCreated(@NonNull Bundle bundle) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/files/PullRequestFilesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/files/PullRequestFilesFragment.java index c62ec636..cd5622b0 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/files/PullRequestFilesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/files/PullRequestFilesFragment.java @@ -25,6 +25,7 @@ import com.fastaccess.ui.modules.main.premium.PremiumActivity; import com.fastaccess.ui.modules.reviews.AddReviewDialogFragment; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.HashMap; import java.util.LinkedHashMap; @@ -42,6 +43,7 @@ public class PullRequestFilesFragment extends BaseFragment toggleMap = new LinkedHashMap<>(); private PullRequestFilesMvp.PatchCallback viewCallback; @@ -107,6 +109,7 @@ public class PullRequestFilesFragment extends BaseFragment super.onError(throwable); } - @Override public void onCallApi(int page, @Nullable Object parameter) { + @Override public boolean onCallApi(int page, @Nullable Object parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); @@ -69,9 +69,9 @@ class PullRequestFilesPresenter extends BasePresenter setCurrentPage(page); if (page > lastPage || lastPage == 0) { sendToView(PullRequestFilesMvp.View::hideProgress); - return; + return false; } - if (repoId == null || login == null) return; + if (repoId == null || login == null) return false; makeRestCall(RestProvider.getPullRequestService(isEnterprise()).getPullRequestFiles(login, repoId, number, page) .flatMap(commitFileModelPageable -> { if (commitFileModelPageable != null) { @@ -83,6 +83,7 @@ class PullRequestFilesPresenter extends BasePresenter return Observable.empty(); }), response -> sendToView(view -> view.onNotifyAdapter(response, page))); + return true; } @Override public void onFragmentCreated(@NonNull Bundle bundle) { diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelineFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelineFragment.java index 794c1030..9a0d5994 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelineFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelineFragment.java @@ -22,18 +22,18 @@ import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; import com.fastaccess.helper.Bundler; import com.fastaccess.provider.rest.loadmore.OnLoadMore; -import com.fastaccess.provider.timeline.CommentsHelper; -import com.fastaccess.ui.adapter.IssuePullsTimelineAdapter; +import com.fastaccess.ui.adapter.IssuesTimelineAdapter; import com.fastaccess.ui.adapter.viewholder.TimelineCommentsViewHolder; import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.editor.EditorActivity; +import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment; import com.fastaccess.ui.modules.repos.issues.issue.details.IssuePagerMvp; import com.fastaccess.ui.modules.repos.reactions.ReactionsDialogFragment; import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.dialog.MessageDialogView; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; -import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerFastScroller; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.HashMap; import java.util.LinkedHashMap; @@ -50,11 +50,12 @@ public class PullRequestTimelineFragment extends BaseFragment toggleMap = new LinkedHashMap<>(); - private IssuePullsTimelineAdapter adapter; + private IssuesTimelineAdapter adapter; private OnLoadMore onLoadMore; + private CommentEditorFragment.CommentListener commentsCallback; private IssuePagerMvp.IssuePrCallback issueCallback; @@ -72,10 +73,19 @@ public class PullRequestTimelineFragment extends BaseFragment items, int page); + @CallOnMainThread void onNotifyAdapter(@Nullable List items, int page); @NonNull OnLoadMore getLoadMore(); @@ -48,15 +50,10 @@ public interface PullRequestTimelineMvp { void onRemove(@NonNull TimelineModel timelineModel); - void onStartNewComment(); - void onShowDeleteMsg(long id); void onReply(User user, String message); - void onReplyOrCreateReview(@Nullable User user, @Nullable String message, int groupPosition, int childPosition, - @NonNull EditReviewCommentModel model); - void showReactionsPopup(@NonNull ReactionTypes type, @NonNull String login, @NonNull String repoId, long idOrNumber, @ReactionsProvider .ReactionType int reactionType); @@ -69,6 +66,14 @@ public interface PullRequestTimelineMvp { @Nullable PullRequest getPullRequest(); void onUpdateHeader(); + + @CallOnMainThread void showReload(); + + void onHandleComment(String text, @Nullable Bundle bundle); + + void onReplyOrCreateReview(@Nullable User user, @Nullable Bundle bundle); + + void onAddReviewComment(@Nullable ReviewCommentModel reviewCommentModel, @NonNull EditReviewCommentModel commentModel); } interface Presenter extends BaseMvp.FAPresenter, BaseViewHolder.OnItemClickListener, @@ -87,5 +92,7 @@ public interface PullRequestTimelineMvp { boolean isMerged(PullRequest pullRequest); boolean isCallingApi(long id, int vId); + + void onHandleComment(@NonNull String text, @Nullable Bundle bundle); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelinePresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelinePresenter.java index f607b4ab..b3c91c78 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelinePresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/pull_requests/pull_request/details/timeline/timeline/PullRequestTimelinePresenter.java @@ -5,31 +5,38 @@ import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.SparseArray; import android.view.View; import android.widget.PopupMenu; import com.fastaccess.R; +import com.fastaccess.data.dao.CommentRequestModel; import com.fastaccess.data.dao.EditReviewCommentModel; import com.fastaccess.data.dao.GroupedReviewModel; import com.fastaccess.data.dao.ReviewCommentModel; import com.fastaccess.data.dao.TimelineModel; import com.fastaccess.data.dao.model.Comment; -import com.fastaccess.data.dao.model.IssueEvent; import com.fastaccess.data.dao.model.Login; import com.fastaccess.data.dao.model.PullRequest; +import com.fastaccess.data.dao.timeline.GenericEvent; +import com.fastaccess.data.dao.timeline.SourceModel; import com.fastaccess.data.dao.types.ReactionTypes; import com.fastaccess.helper.ActivityHelper; import com.fastaccess.helper.BundleConstant; +import com.fastaccess.helper.Bundler; import com.fastaccess.helper.InputHelper; import com.fastaccess.provider.rest.RestProvider; import com.fastaccess.provider.scheme.SchemeParser; import com.fastaccess.provider.timeline.CommentsHelper; import com.fastaccess.provider.timeline.ReactionsProvider; +import com.fastaccess.provider.timeline.TimelineConverter; import com.fastaccess.ui.base.mvp.BaseMvp; import com.fastaccess.ui.base.mvp.presenter.BasePresenter; +import com.fastaccess.ui.modules.filter.issues.FilterIssuesActivity; import com.fastaccess.ui.modules.repos.issues.create.CreateIssueActivity; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import io.reactivex.Observable; @@ -40,15 +47,17 @@ import io.reactivex.Observable; public class PullRequestTimelinePresenter extends BasePresenter implements PullRequestTimelineMvp.Presenter { private ArrayList timeline = new ArrayList<>(); + private SparseArray pages = new SparseArray<>(); private ReactionsProvider reactionsProvider; private int page; private int previousTotal; private int lastPage = Integer.MAX_VALUE; @Override public void onItemClick(int position, View v, TimelineModel item) { - if (getView() != null && getView().getPullRequest() != null) { + if (getView() == null) return; + PullRequest pullRequest = getView().getPullRequest(); + if (pullRequest != null) { if (item.getType() == TimelineModel.COMMENT) { - PullRequest pullRequest = getView().getPullRequest(); if (v.getId() == R.id.commentMenu) { PopupMenu popupMenu = new PopupMenu(v.getContext(), v); popupMenu.inflate(R.menu.comments_menu); @@ -61,7 +70,7 @@ public class PullRequestTimelinePresenter extends BasePresenter { if (getView() == null) return false; if (item1.getItemId() == R.id.reply) { - getView().onReply(item.getPullRequest().getUser(), item.getPullRequest().getBody()); + getView().onReply(item.getPullRequest().getUser(), item.getPullRequest().getBodyHtml()); } else if (item1.getItemId() == R.id.edit) { Activity activity = ActivityHelper.getActivity(v.getContext()); if (activity == null) return false; @@ -105,14 +136,18 @@ public class PullRequestTimelinePresenter extends BasePresenter { + }); + } else { + EditReviewCommentModel commentModel = bundle.getParcelable(BundleConstant.REVIEW_EXTRA); + if (commentModel != null) { + CommentRequestModel commentRequestModel = new CommentRequestModel(); + commentRequestModel.setBody(text); + commentRequestModel.setInReplyTo(commentModel.getInReplyTo()); + makeRestCall(RestProvider.getReviewService(isEnterprise()) + .submitComment(pullRequest.getLogin(), pullRequest.getRepoId(), pullRequest.getNumber(), commentRequestModel), + reviewCommentModel -> { + sendToView(view -> view.onAddReviewComment(reviewCommentModel, commentModel)); + }); + } + } + } + } + @Override public boolean isPreviouslyReacted(long commentId, int vId) { return getReactionsProvider().isPreviouslyReacted(commentId, vId); } @@ -230,7 +296,12 @@ public class PullRequestTimelinePresenter extends BasePresenter view.getLoadMore().reset()); + pages.clear(); } if (page > lastPage || lastPage == 0) { sendToView(PullRequestTimelineMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); if (parameter.getHead() != null) { - loadEverything(login, repoId, number, parameter.getHead().getSha(), parameter.isMergeable(), page); - } - } - - private void loadEverything(String login, String repoId, int number, @NonNull String sha, boolean isMergeable, int page) { - Observable> observable; - if (page > 1) { - observable = RestProvider.getIssueService(isEnterprise()).getIssueComments(login, repoId, number, page) - .map(comments -> { - lastPage = comments != null ? comments.getLast() : 0; - return TimelineModel.construct(comments != null ? comments.getItems() : null); - }); - } else { - observable = Observable.zip(RestProvider.getIssueService(isEnterprise()).getTimeline(login, repoId, number), - RestProvider.getIssueService(isEnterprise()).getIssueComments(login, repoId, number, page), - RestProvider.getPullRequestService(isEnterprise()).getPullStatus(login, repoId, sha), - RestProvider.getReviewService(isEnterprise()).getReviews(login, repoId, number), - RestProvider.getReviewService(isEnterprise()).getPrReviewComments(login, repoId, number), - (issueEventPageable, commentPageable, statuses, reviews, reviewComments) -> { - if (statuses != null) { - statuses.setMergable(isMergeable); + Observable> observable = Observable.zip(RestProvider.getIssueService(isEnterprise()) + .getTimeline(login, repoId, number, page), RestProvider.getReviewService(isEnterprise()) + .getPrReviewComments(login, repoId, number), + RestProvider.getPullRequestService(isEnterprise()).getPullStatus(login, repoId, parameter.getHead().getRef()), + (response, comments, status) -> { + if (response != null) { + lastPage = response.getLast(); + List models = TimelineConverter.INSTANCE.convert(response.getItems(), comments); + if (page == 1 && status != null) { + models.add(0, new TimelineModel(status)); + } + return models; + } else { + return Collections.emptyList(); } - lastPage = commentPageable != null ? commentPageable.getLast() : 0; - return TimelineModel.construct(commentPageable != null ? commentPageable.getItems() : null, - issueEventPageable.getItems(), statuses, reviews.getItems(), reviewComments.getItems()); }); + makeRestCall(observable, timeline -> sendToView(view -> view.onNotifyAdapter(timeline, page))); + return true; } - makeRestCall(observable, models -> sendToView(view -> view.onNotifyAdapter(models, page))); + return false; } +// +// @Nullable private Observable getTimelineObservable(Response response, +// boolean isMergeable) { +// if (!response.hasErrors()) { +// PullRequestTimelineQuery.Data data = response.data(); +// if (data != null) { +// PullRequestTimelineQuery.Repository repo = data.repository(); +// PullRequestTimelineQuery.PullRequest pullRequest = repo != null ? repo.pullRequest() : null; +// if (pullRequest != null) { +// PullRequestTimelineQuery.Timeline timeline = pullRequest.timeline(); +// lastPage = timeline.pageInfo().hasNextPage() ? Integer.MAX_VALUE : 0; +// pages.clear(); +// ArrayList models = new ArrayList<>(); +// PullRequestTimelineQuery.PullRequestCommits pullRequestCommits = pullRequest.pullRequestCommits(); +// List commits = pullRequestCommits.pullRequestCommit(); +// if (commits != null && !commits.isEmpty() && page <= 1) { +// PullRequestTimelineQuery.Status status = commits.get(0).commit().status(); +// if (status != null) { +// models.add(new PullRequestTimelineModel(status, isMergeable)); +// } +// } +// List edges = timeline.edges(); +// if (edges != null) { +// Stream.of(edges).forEachIndexed((i, edge) -> pages.append(i, edge.cursor())); +// } +// List nodes = timeline.nodes(); +// if (nodes != null) { +// for (PullRequestTimelineQuery.Node node : nodes) { +// models.add(new PullRequestTimelineModel(node)); +// } +// } +// return RxHelper.getObservable(Observable.fromIterable(models)); +// } +// } +// } +// return null; +// } +// +// @NonNull private PullRequestTimelineQuery getTimelineBuilder(@NonNull String login, @NonNull String repoId, int number, int page) { +// return PullRequestTimelineQuery.builder() +// .owner(login) +// .name(repoId) +// .number(number) +// .page(getPage()) +// .build(); +// } +// +// @Nullable private String getPage() { +// return pages.size() != 0 ? pages.valueAt(pages.size() - 1) : ""; +// } +// +// private void loadEverything(@NonNull String login, @NonNull String repoId, int number, +// @NonNull String sha, boolean isMergeable, int page) { +// PullRequestTimelineQuery query = getTimelineBuilder(login, repoId, number, page); +// ApolloCall apolloCall = App.getInstance().getApolloClient().query(query); +// Observable observable = Rx2Apollo.from(apolloCall) +// .flatMap(response -> { +// Observable models = getTimelineObservable(response, isMergeable); +// return models != null ? models : RxHelper.getObservable(Observable.fromIterable(new ArrayList<>())); +// }); +// makeRestCall(observable.toList().toObservable(), +// pullRequestTimelineModels -> sendToView(view -> view.onNotifyAdapter(pullRequestTimelineModels, page))); +// } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/reactions/ReactionsDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/reactions/ReactionsDialogFragment.java index e64deea5..691c7f82 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/reactions/ReactionsDialogFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/reactions/ReactionsDialogFragment.java @@ -22,6 +22,7 @@ import com.fastaccess.ui.widgets.AppbarRefreshLayout; import com.fastaccess.ui.widgets.SpannableBuilder; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -39,6 +40,7 @@ public class ReactionsDialogFragment extends BaseDialogFragment items, int page) { @@ -94,7 +97,7 @@ public class ReactionsDialogFragment extends BaseDialogFragment view.getLoadMore().reset()); } if (page > lastPage || lastPage == 0 || (login == null || repoId == null || reactionType == null)) { sendToView(ReactionsDialogMvp.View::hideProgress); - return; + return false; } setCurrentPage(page); Observable> observable = null; @@ -104,6 +104,7 @@ public class ReactionsDialogPresenter extends BasePresenter(), WikiMvp.View { - val navMenu: NavigationView by bindView(R.id.wikiSidebar) - val drawerLayout: DrawerLayout by bindView(R.id.drawer) - val progressbar: ProgressBar by bindView(R.id.progress) - val stateLayout: StateLayout by bindView(R.id.stateLayout) - val webView: PrettifyWebView by bindView(R.id.webView) - + @BindView(R.id.wikiSidebar) lateinit var navMenu: NavigationView + @BindView(R.id.drawer) lateinit var drawerLayout: DrawerLayout + @BindView(R.id.progress) lateinit var progressbar: ProgressBar + @BindView(R.id.stateLayout) lateinit var stateLayout: StateLayout + @BindView(R.id.webView) lateinit var webView: PrettifyWebView @State var wiki = WikiContentModel(null, null, arrayListOf()) @State var selectedTitle: String = "Home" @@ -50,7 +52,15 @@ class WikiActivity : BaseActivity(), WikiMvp.View { loadMenu() } if (wiki.content != null) { - webView.setGithubContent(wiki.content, null, true) + val baseUrl = Uri.Builder().scheme("https") + .authority(LinkParserHelper.HOST_DEFAULT) + .appendPath(presenter.login) + .appendPath(presenter.repoId) + .appendPath("wiki") + .build() + .toString() + Logger.e(baseUrl) + webView.setWikiContent(wiki.content, baseUrl) } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/wiki/WikiPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/repos/wiki/WikiPresenter.kt index a24b6ee3..659abc19 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/repos/wiki/WikiPresenter.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/repos/wiki/WikiPresenter.kt @@ -4,7 +4,6 @@ import android.content.Intent import com.fastaccess.data.dao.wiki.WikiContentModel import com.fastaccess.data.dao.wiki.WikiSideBarModel import com.fastaccess.helper.BundleConstant -import com.fastaccess.helper.Logger import com.fastaccess.helper.RxHelper import com.fastaccess.provider.rest.jsoup.JsoupProvider import com.fastaccess.ui.base.mvp.presenter.BasePresenter @@ -47,13 +46,13 @@ class WikiPresenter : BasePresenter(), WikiMvp.Presenter { val wikiWrapper = document.select("#wiki-wrapper") if (wikiWrapper.isNotEmpty()) { val cloneUrl = wikiWrapper.select(".clone-url") - val bottomRightBar = wikiWrapper.select(".wiki-custom-sidebar") +// val bottomRightBar = wikiWrapper.select(".wiki-custom-sidebar") if (cloneUrl.isNotEmpty()) { cloneUrl.remove() } - if (bottomRightBar.isNotEmpty()) { - bottomRightBar.remove() - } +// if (bottomRightBar.isNotEmpty()) { +// bottomRightBar.remove() +// } val headerHtml = wikiWrapper.select(".gh-header .gh-header-meta") val revision = headerHtml.select("a.history") if (revision.isNotEmpty()) { @@ -61,7 +60,7 @@ class WikiPresenter : BasePresenter(), WikiMvp.Presenter { } val header = "
${headerHtml.html()}
" val wikiContent = wikiWrapper.select(".wiki-content") - val content = header + wikiContent.select(".markdown-body").html() + val content = header + wikiContent.select(".wiki-body").html() val rightBarList = wikiContent.select(".wiki-pages").select("li") val sidebarList = arrayListOf() if (rightBarList.isNotEmpty()) { @@ -71,7 +70,6 @@ class WikiPresenter : BasePresenter(), WikiMvp.Presenter { sidebarList.add(WikiSideBarModel(sidebarTitle, sidebarLink)) } } - Logger.d(header) s.onNext(WikiContentModel(content, "", sidebarList)) } else { s.onNext(WikiContentModel("

No Wiki

", "", arrayListOf())) diff --git a/app/src/main/java/com/fastaccess/ui/modules/reviews/AddReviewDialogFragment.kt b/app/src/main/java/com/fastaccess/ui/modules/reviews/AddReviewDialogFragment.kt index 9ba284dc..26b716a2 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/reviews/AddReviewDialogFragment.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/reviews/AddReviewDialogFragment.kt @@ -8,6 +8,7 @@ import android.support.v4.content.ContextCompat import android.support.v7.widget.Toolbar import android.view.View import android.widget.TextView +import butterknife.BindView import com.fastaccess.R import com.fastaccess.data.dao.CommitLinesModel import com.fastaccess.helper.BundleConstant @@ -25,11 +26,12 @@ import com.fastaccess.ui.widgets.SpannableBuilder */ class AddReviewDialogFragment : BaseDialogFragment>() { - val toolbar: Toolbar by lazy { view!!.findViewById(R.id.toolbar) } - val textView: TextView by lazy { view!!.findViewById(R.id.text) } - val lineNo: TextView by lazy { view!!.findViewById(R.id.lineNo) } - val editText: TextInputLayout by lazy { view!!.findViewById(R.id.editText) } - val spacePattern = "\\s+".toRegex() + @BindView(R.id.toolbar) lateinit var toolbar: Toolbar + @BindView(R.id.text) lateinit var textView: TextView + @BindView(R.id.lineNo) lateinit var lineNo: TextView + @BindView(R.id.editText) lateinit var editText: TextInputLayout + + private val spacePattern = "\\s+".toRegex() private var commentCallback: ReviewCommentListener? = null diff --git a/app/src/main/java/com/fastaccess/ui/modules/reviews/changes/ReviewChangesActivity.kt b/app/src/main/java/com/fastaccess/ui/modules/reviews/changes/ReviewChangesActivity.kt index 58a7799c..9c0ab2f5 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/reviews/changes/ReviewChangesActivity.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/reviews/changes/ReviewChangesActivity.kt @@ -10,13 +10,13 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.Spinner +import butterknife.BindView import com.evernote.android.state.State import com.fastaccess.R import com.fastaccess.data.dao.ReviewRequestModel import com.fastaccess.helper.* import com.fastaccess.provider.theme.ThemeEngine import com.fastaccess.ui.base.BaseActivity -import com.fastaccess.ui.widgets.bindView import com.fastaccess.ui.widgets.dialog.ProgressDialogFragment /** @@ -25,9 +25,9 @@ import com.fastaccess.ui.widgets.dialog.ProgressDialogFragment class ReviewChangesActivity : BaseActivity(), ReviewChangesMvp.View { - val toolbar: Toolbar by bindView(R.id.toolbar) - val spinner: Spinner by bindView(R.id.reviewMethod) - val editText: TextInputLayout by bindView(R.id.editText) + @BindView(R.id.toolbar) lateinit var toolbar: Toolbar + @BindView(R.id.reviewMethod) lateinit var spinner: Spinner + @BindView(R.id.editText) lateinit var editText: TextInputLayout @State var reviewRequest: ReviewRequestModel? = null @State var repoId: String? = null diff --git a/app/src/main/java/com/fastaccess/ui/modules/search/SearchActivity.java b/app/src/main/java/com/fastaccess/ui/modules/search/SearchActivity.java index 3b5c9697..5339f4ba 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/search/SearchActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/search/SearchActivity.java @@ -1,5 +1,7 @@ package com.fastaccess.ui.modules.search; +import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -45,11 +47,18 @@ public class SearchActivity extends BaseActivity tabsCountSet = new LinkedHashSet<>(); + private NumberFormat numberFormat = NumberFormat.getNumberInstance(); private ArrayAdapter adapter; + + public static Intent getIntent(@NonNull Context context, @Nullable String query) { + Intent intent = new Intent(context, SearchActivity.class); + intent.putExtra("search", query); + return intent; + } + @OnTextChanged(value = R.id.searchEditText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) void onTextChange(Editable s) { String text = s.toString(); @@ -60,8 +69,12 @@ public class SearchActivity extends BaseActivity onLoadMore; private SearchCodeAdapter adapter; private SearchMvp.View countCallback; @@ -94,6 +96,7 @@ public class SearchCodeFragment extends BaseFragment implements S this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } setCurrentPage(page); - if (page > lastPage || lastPage == 0) { + if (page > lastPage || lastPage == 0 || parameter == null) { sendToView(SearchCodeMvp.View::hideProgress); - return; - } - if (parameter == null) { - return; + return false; } makeRestCall(RestProvider.getSearchService(isEnterprise()).searchCode(parameter, page), response -> { @@ -58,6 +55,7 @@ class SearchCodePresenter extends BasePresenter implements S view.onSetTabCount(response.getTotalCount()); }); }); + return true; } @NonNull @Override public ArrayList getCodes() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/search/issues/SearchIssuesFragment.java b/app/src/main/java/com/fastaccess/ui/modules/search/issues/SearchIssuesFragment.java index e073ab5c..fb329610 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/search/issues/SearchIssuesFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/search/issues/SearchIssuesFragment.java @@ -19,6 +19,7 @@ import com.fastaccess.ui.modules.repos.extras.popup.IssuePopupFragment; import com.fastaccess.ui.modules.search.SearchMvp; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -34,6 +35,7 @@ public class SearchIssuesFragment extends BaseFragment onLoadMore; private IssuesAdapter adapter; private SearchMvp.View countCallback; @@ -91,6 +93,7 @@ public class SearchIssuesFragment extends BaseFragment implemen this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } setCurrentPage(page); - if (page > lastPage || lastPage == 0) { + if (page > lastPage || lastPage == 0 || parameter == null) { sendToView(SearchIssuesMvp.View::hideProgress); - return; - } - if (parameter == null) { - return; + return false; } makeRestCall(RestProvider.getSearchService(isEnterprise()).searchIssues(parameter, page), response -> { @@ -59,6 +56,7 @@ class SearchIssuesPresenter extends BasePresenter implemen view.onSetTabCount(response.getTotalCount()); }); }); + return true; } @NonNull @Override public ArrayList getIssues() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/search/repos/SearchReposFragment.java b/app/src/main/java/com/fastaccess/ui/modules/search/repos/SearchReposFragment.java index e168c900..f5856eec 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/search/repos/SearchReposFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/search/repos/SearchReposFragment.java @@ -18,6 +18,7 @@ import com.fastaccess.ui.base.BaseFragment; import com.fastaccess.ui.modules.search.SearchMvp; import com.fastaccess.ui.widgets.StateLayout; import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView; +import com.fastaccess.ui.widgets.recyclerview.scroll.RecyclerViewFastScroller; import java.util.List; @@ -33,6 +34,7 @@ public class SearchReposFragment extends BaseFragment onLoadMore; private ReposAdapter adapter; private SearchMvp.View countCallback; @@ -93,6 +95,7 @@ public class SearchReposFragment extends BaseFragment implements this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } setCurrentPage(page); - if (page > lastPage || lastPage == 0) { + if (page > lastPage || lastPage == 0 || parameter == null) { sendToView(SearchReposMvp.View::hideProgress); - return; - } - if (parameter == null) { - return; + return false; } makeRestCall(RestProvider.getSearchService(isEnterprise()).searchRepositories(parameter, page), response -> { @@ -59,6 +56,7 @@ class SearchReposPresenter extends BasePresenter implements view.onSetTabCount(response.getTotalCount()); }); }); + return true; } @NonNull @Override public ArrayList getRepos() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/search/repos/files/SearchFileActivity.java b/app/src/main/java/com/fastaccess/ui/modules/search/repos/files/SearchFileActivity.java index 8f8792aa..1e1d1a58 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/search/repos/files/SearchFileActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/search/repos/files/SearchFileActivity.java @@ -7,9 +7,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatSpinner; import android.text.Editable; -import android.view.KeyEvent; import android.view.View; -import android.view.inputmethod.EditorInfo; import com.fastaccess.R; import com.fastaccess.helper.AnimHelper; @@ -48,12 +46,36 @@ public class SearchFileActivity extends BaseActivity onLoadMore; private UsersAdapter adapter; private SearchMvp.View countCallback; @@ -91,6 +93,7 @@ public class SearchUsersFragment extends BaseFragment implements this.previousTotal = previousTotal; } - @Override public void onCallApi(int page, @Nullable String parameter) { + @Override public boolean onCallApi(int page, @Nullable String parameter) { if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); } setCurrentPage(page); - if (page > lastPage || lastPage == 0) { + if (page > lastPage || lastPage == 0 || parameter == null) { sendToView(SearchUsersMvp.View::hideProgress); - return; - } - if (parameter == null) { - return; + return false; } makeRestCall(RestProvider.getSearchService(isEnterprise()).searchUsers(parameter, page), response -> { @@ -58,6 +55,7 @@ class SearchUsersPresenter extends BasePresenter implements view.onSetTabCount(response.getTotalCount()); }); }); + return true; } @NonNull @Override public ArrayList getUsers() { diff --git a/app/src/main/java/com/fastaccess/ui/modules/settings/SlackBottomSheetDialog.java b/app/src/main/java/com/fastaccess/ui/modules/settings/SlackBottomSheetDialog.java index 6e9213f2..91cf9aed 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/settings/SlackBottomSheetDialog.java +++ b/app/src/main/java/com/fastaccess/ui/modules/settings/SlackBottomSheetDialog.java @@ -51,8 +51,7 @@ public class SlackBottomSheetDialog extends BaseBottomSheetDialog { @OnClick({R.id.cancel, R.id.ok}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.ok: -// view.getContext().startService(new Intent(getContext().getApplicationContext(), SlackInvitationService.class)); - ActivityHelper.startCustomTab(getActivity(), "http://rebrand.ly/fasthub"); + ActivityHelper.startCustomTab(getActivity(), "http://rebrand.ly/fasthub-slack"); break; } if (listener != null) listener.onDismissed(); diff --git a/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryActivity.java b/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryActivity.java index 283be818..b3de5f22 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryActivity.java +++ b/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryActivity.java @@ -41,7 +41,7 @@ public class SettingsCategoryActivity extends BaseActivity implements SettingsCa settingsType = bundle.getInt(BundleConstant.ITEM); getSupportFragmentManager() .beginTransaction() - .replace(R.id.settingsContainer, new SettingsCategoryFragment()) + .replace(R.id.settingsContainer, new SettingsCategoryFragment(), "SettingsCategoryFragment") .commit(); } setTitle(title); diff --git a/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryFragment.java b/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryFragment.java index 77b53600..197f9ceb 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/settings/category/SettingsCategoryFragment.java @@ -62,10 +62,10 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement private String appColor; private String appLanguage; - private Preference signatureVia; private Preference notificationTime; private Preference notificationRead; private Preference notificationSound; + private Preference notificationSoundPath; private SettingsCallback settingsCallback; @Override public void onAttach(Context context) { @@ -111,12 +111,14 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement getPreferenceScreen().addPreference(notificationTime); getPreferenceScreen().addPreference(notificationRead); getPreferenceScreen().addPreference(notificationSound); + getPreferenceScreen().addPreference(notificationSoundPath); NotificationSchedulerJobTask.scheduleJob(App.getInstance(), PrefGetter.getNotificationTaskDuration(), true); } else { getPreferenceScreen().removePreference(notificationTime); getPreferenceScreen().removePreference(notificationRead); getPreferenceScreen().removePreference(notificationSound); + getPreferenceScreen().removePreference(notificationSoundPath); NotificationSchedulerJobTask.scheduleJob(App.getInstance(), -1, true); } return true; @@ -141,15 +143,6 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement return true; callback.onThemeChanged(); return true; - } else if (preference.getKey().equalsIgnoreCase("sent_via_enabled")) { - if ((boolean) newValue) - getPreferenceScreen().removePreference(signatureVia); - else - getPreferenceScreen().addPreference(signatureVia); - return true; - } else if (preference.getKey().equalsIgnoreCase("enable_ads")) { - callback.onThemeChanged(); - return true; } return false; } @@ -202,14 +195,17 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement restoreData(data); } else if (requestCode == SOUND_REQUEST_CODE) { Uri ringtone = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); - findPreference("notification_sound_path").setDefaultValue(ringtone.toString()); + if (notificationSoundPath != null && notificationSoundPath.isVisible()) { + notificationSoundPath.setDefaultValue(ringtone.toString()); + } } } } @Override public void onSoundSelected(Uri uri) { PrefGetter.setNotificationSound(uri); - findPreference("notification_sound_path").setSummary(FileHelper.getRingtoneName(getContext(), uri)); + if (notificationSoundPath != null && notificationSoundPath.isVisible()) + notificationSoundPath.setSummary(FileHelper.getRingtoneName(getContext(), uri)); } private void showFileChooser() { @@ -273,13 +269,6 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement private void addBehaviour() { addPreferencesFromResource(R.xml.behaviour_settings); - findPreference("sent_via_enabled").setOnPreferenceChangeListener(this); - findPreference("enable_ads").setOnPreferenceChangeListener(this); - signatureVia = findPreference("sent_via"); - if (PrefHelper.getBoolean("sent_via_enabled")) { - signatureVia.setDefaultValue(false); - getPreferenceScreen().removePreference(signatureVia); - } } private void addNotifications() { @@ -287,18 +276,20 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement notificationTime = findPreference("notificationTime"); notificationRead = findPreference("markNotificationAsRead"); notificationSound = findPreference("notificationSound"); - findPreference("notification_sound_path").setSummary(FileHelper.getRingtoneName(getContext(), PrefGetter.getNotificationSound())); - findPreference("notification_sound_path").setOnPreferenceClickListener(preference -> { + notificationTime.setOnPreferenceChangeListener(this); + findPreference("notificationEnabled").setOnPreferenceChangeListener(this); + notificationSoundPath = findPreference("notification_sound_path"); + notificationSoundPath.setSummary(FileHelper.getRingtoneName(getContext(), PrefGetter.getNotificationSound())); + notificationSoundPath.setOnPreferenceClickListener(preference -> { NotificationSoundBottomSheet.Companion.newInstance(FileHelper.getRingtoneName(getContext(), PrefGetter.getNotificationSound())) .show(getChildFragmentManager(), "NotificationSoundBottomSheet"); return true; }); - findPreference("notificationTime").setOnPreferenceChangeListener(this); - findPreference("notificationEnabled").setOnPreferenceChangeListener(this); if (!PrefHelper.getBoolean("notificationEnabled")) { getPreferenceScreen().removePreference(notificationTime); getPreferenceScreen().removePreference(notificationRead); getPreferenceScreen().removePreference(notificationSound); + getPreferenceScreen().removePreference(notificationSoundPath); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/settings/sound/NotificationSoundBottomSheet.kt b/app/src/main/java/com/fastaccess/ui/modules/settings/sound/NotificationSoundBottomSheet.kt index 8614b2f1..7b8babf0 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/settings/sound/NotificationSoundBottomSheet.kt +++ b/app/src/main/java/com/fastaccess/ui/modules/settings/sound/NotificationSoundBottomSheet.kt @@ -9,6 +9,7 @@ import android.view.ViewGroup import android.widget.Button import android.widget.RadioButton import android.widget.RadioGroup +import butterknife.BindView import com.fastaccess.R import com.fastaccess.data.dao.NotificationSoundModel import com.fastaccess.helper.BundleConstant @@ -22,12 +23,13 @@ import com.fastaccess.ui.widgets.FontTextView class NotificationSoundBottomSheet : BaseMvpBottomSheetDialogFragment(), NotificationSoundMvp.View { - val title: FontTextView by lazy { view!!.findViewById(R.id.title) } - val radioGroup: RadioGroup by lazy { view!!.findViewById(R.id.picker) } - val okButton: Button by lazy { view!!.findViewById