this commit fixes #799 , fixes #794 and improves readme parsing

This commit is contained in:
kosh 2017-07-28 17:01:55 +08:00
parent 0a9b65fade
commit 20fb10738b
15 changed files with 210 additions and 187 deletions

View File

@ -176,7 +176,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

View File

@ -18,14 +18,14 @@ import lombok.Setter;
@Getter @Setter public class PullRequestStatusModel extends Timeline implements Parcelable {
private StatusStateType state;
private String sha;
private int totalCount;
private List<StatusesModel> statuses;
private String commitUrl;
private String url;
private boolean mergable;
private Date createdAt;
StatusStateType state;
String sha;
int totalCount;
List<StatusesModel> statuses;
String commitUrl;
String url;
boolean mergable;
Date createdAt;
public PullRequestStatusModel() {}

View File

@ -17,23 +17,23 @@ import lombok.Setter;
@Getter @Setter public class ReviewCommentModel extends Timeline implements Parcelable {
private long id;
private String url;
private long pullRequestReviewId;
private String diffHunk;
private String path;
private int position;
private int originalPosition;
private String commitId;
private String originalCommitId;
private User user;
private String bodyHtml;
private String body;
private Date createdAt;
private Date updatedAt;
private String htmlUrl;
private String pullRequestUrl;
private ReactionsModel reactions;
long id;
String url;
long pullRequestReviewId;
String diffHunk;
String path;
int position;
int originalPosition;
String commitId;
String originalCommitId;
User user;
String bodyHtml;
String body;
Date createdAt;
Date updatedAt;
String htmlUrl;
String pullRequestUrl;
ReactionsModel reactions;
public ReviewCommentModel() {}

View File

@ -17,15 +17,15 @@ import lombok.Setter;
@Getter @Setter public class ReviewModel implements Parcelable {
private long id;
private User user;
private String bodyHtml;
private String state;
private Date submittedAt;
private String commitId;
private String diffText;
private List<ReviewCommentModel> comments;
private ReactionsModel reactions;
long id;
User user;
String bodyHtml;
String state;
Date submittedAt;
String commitId;
String diffText;
List<ReviewCommentModel> comments;
ReactionsModel reactions;
public ReviewModel() {}

View File

@ -14,7 +14,6 @@ import java.util.List;
import io.reactivex.Observable;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
@ -22,7 +21,7 @@ import lombok.Setter;
* Created by Kosh on 30 Mar 2017, 9:03 PM
*/
@Getter @Setter @NoArgsConstructor public class TimelineModel implements Parcelable {
@Getter @Setter public class TimelineModel implements Parcelable {
public static final int HEADER = 0;
public static final int LINE_COMMENT = 1;
public static final int EVENT = 2;
@ -30,14 +29,14 @@ import lombok.Setter;
public static final int STATUS = 4;
public static final int REVIEW = 5;
private IssueEventType event;
private Comment comment;
private GenericEvent genericEvent;
private ReviewCommentModel reviewComment;
private PullRequestStatusModel status;
private Issue issue;
private PullRequest pullRequest;
private ReviewModel review;
public IssueEventType event;
public Comment comment;
public GenericEvent genericEvent;
public ReviewCommentModel reviewComment;
public PullRequestStatusModel status;
public Issue issue;
public PullRequest pullRequest;
public ReviewModel review;
public TimelineModel(Issue issue) {
this.issue = issue;
@ -61,6 +60,8 @@ import lombok.Setter;
this.event = IssueEventType.line_commented;
}
public TimelineModel() {}
public int getType() {
if (getEvent() != null) {
switch (getEvent()) {

View File

@ -25,31 +25,31 @@ import lombok.Setter;
@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<ParentsModel> parents;
private IssueEventType event;
long id;
String url;
String commitId;
String commitUrl;
String message;
String sha;
String htmlUrl;
Date createdAt;
User actor;
User requestedReviewer;
User reviewRequester;
User assigner;
User assignee;
User author;
User committer;
LabelModel label;
TeamsModel requestedTeam;
MilestoneModel milestone;
RenameModel rename;
SourceModel source;
Issue issue;
PullRequest pullRequest;
ParentsModel tree;
List<ParentsModel> parents;
IssueEventType event;
@Override public int describeContents() { return 0; }

View File

@ -1,75 +0,0 @@
package com.fastaccess.provider.timeline;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.fastaccess.data.dao.ReviewCommentModel;
import com.fastaccess.data.dao.ReviewModel;
import com.fastaccess.data.dao.TimelineModel;
import com.fastaccess.data.dao.model.Comment;
import com.fastaccess.data.dao.timeline.GenericEvent;
import com.fastaccess.data.dao.types.IssueEventType;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.provider.rest.RestProvider;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.List;
import io.reactivex.Observable;
/**
* Created by kosh on 26/07/2017.
*/
public class TimelineConverter {
@NonNull public static Observable<TimelineModel> convert(@Nullable List<JsonObject> jsonObjects) {
if (jsonObjects == null) return Observable.empty();
Gson gson = RestProvider.gson;
return Observable.fromIterable(jsonObjects)
.map(jsonObject -> {
String event = jsonObject.get("event").getAsString();
TimelineModel timeline = new TimelineModel();
if (!InputHelper.isEmpty(event)) {
IssueEventType type = IssueEventType.getType(event);
timeline.setEvent(type);
if (type != null) {
if (type == IssueEventType.commented) {
timeline.setComment(getComment(jsonObject, gson));
} else if (type == IssueEventType.line_commented) {
timeline.setReviewComment(getReviewComment(jsonObject, gson));
} else if (type == IssueEventType.reviewed) {
timeline.setReview(getReview(jsonObject, gson));
} else {
timeline.setGenericEvent(getGenericEvent(jsonObject, gson));
}
}
} else {
timeline.setGenericEvent(getGenericEvent(jsonObject, gson));
}
return timeline;
})
.filter(timeline -> timeline != null && filterEvents(timeline.getEvent()));
}
private static ReviewModel getReview(@NonNull JsonObject object, @NonNull Gson gson) {
return gson.fromJson(object, ReviewModel.class);
}
private static GenericEvent getGenericEvent(@NonNull JsonObject object, @NonNull Gson gson) {
return gson.fromJson(object, GenericEvent.class);
}
private static ReviewCommentModel getReviewComment(@NonNull JsonObject object, @NonNull Gson gson) {
return gson.fromJson(object, ReviewCommentModel.class);
}
private static Comment getComment(@NonNull JsonObject object, @NonNull Gson gson) {
return gson.fromJson(object, Comment.class);
}
private static boolean filterEvents(@Nullable IssueEventType type) {
return type != IssueEventType.subscribed && type != IssueEventType.unsubscribed && type != IssueEventType.mentioned;
}
}

View File

@ -0,0 +1,70 @@
package com.fastaccess.provider.timeline
import com.fastaccess.data.dao.ReviewCommentModel
import com.fastaccess.data.dao.ReviewModel
import com.fastaccess.data.dao.TimelineModel
import com.fastaccess.data.dao.model.Comment
import com.fastaccess.data.dao.timeline.GenericEvent
import com.fastaccess.data.dao.types.IssueEventType
import com.fastaccess.helper.InputHelper
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<JsonObject>?): Observable<TimelineModel> {
if (jsonObjects == null) return Observable.empty<TimelineModel>()
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 if (type == IssueEventType.line_commented) {
timeline.reviewComment = getReviewComment(jsonObject, gson)
} else if (type == IssueEventType.reviewed) {
timeline.review = getReview(jsonObject, gson)
} else {
timeline.genericEvent = getGenericEvent(jsonObject, gson)
}
}
} else {
timeline.genericEvent = getGenericEvent(jsonObject, gson)
}
timeline
}
.filter { filterEvents(it.event) }
}
private fun getReview(jsonObject: JsonObject, gson: Gson): ReviewModel {
return gson.fromJson(jsonObject, ReviewModel::class.java)
}
private fun getGenericEvent(jsonObject: JsonObject, gson: Gson): GenericEvent {
return gson.fromJson(jsonObject, GenericEvent::class.java)
}
private fun getReviewComment(jsonObject: JsonObject, gson: Gson): ReviewCommentModel {
return gson.fromJson(jsonObject, ReviewCommentModel::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 != IssueEventType.subscribed && type != IssueEventType.unsubscribed && type != IssueEventType.mentioned
}
}

View File

@ -236,7 +236,7 @@ import lombok.Getter;
if (response != null) {
lastPage = response.getLast();
}
return TimelineConverter.convert(response != null ? response.getItems() : null);
return TimelineConverter.INSTANCE.convert(response != null ? response.getItems() : null);
}).toList()
.toObservable();
makeRestCall(observable, timeline -> sendToView(view -> view.onNotifyAdapter(timeline, page)));

View File

@ -299,7 +299,7 @@ public class PullRequestTimelinePresenter extends BasePresenter<PullRequestTimel
.getTimeline(login, repoId, number, page)
.flatMap(response -> {
lastPage = response != null ? response.getLast() : 0;
return TimelineConverter.convert(response != null ? response.getItems() : null);
return TimelineConverter.INSTANCE.convert(response != null ? response.getItems() : null);
})
.toList()
.toObservable()

View File

@ -2,6 +2,7 @@ package com.fastaccess.ui.modules.repos.wiki
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.support.design.widget.NavigationView
import android.support.v4.widget.DrawerLayout
@ -16,6 +17,8 @@ import com.fastaccess.data.dao.NameParser
import com.fastaccess.data.dao.wiki.WikiContentModel
import com.fastaccess.helper.BundleConstant
import com.fastaccess.helper.Bundler
import com.fastaccess.helper.Logger
import com.fastaccess.provider.scheme.LinkParserHelper
import com.fastaccess.ui.base.BaseActivity
import com.fastaccess.ui.modules.repos.RepoPagerActivity
import com.fastaccess.ui.widgets.StateLayout
@ -50,7 +53,15 @@ class WikiActivity : BaseActivity<WikiMvp.View, WikiPresenter>(), 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)
}
}

View File

@ -59,6 +59,7 @@ class WikiPresenter : BasePresenter<WikiMvp.View>(), WikiMvp.Presenter {
if (revision.isNotEmpty()) {
revision.remove()
}
wikiWrapper.select(".js-wiki-more-pages-link").remove()
val header = "<div class='gh-header-meta'>${headerHtml.html()}</div>"
val wikiContent = wikiWrapper.select(".wiki-content")
val content = header + wikiContent.select(".markdown-body").html()

View File

@ -147,9 +147,6 @@ public class SettingsCategoryFragment extends PreferenceFragmentCompat implement
else
getPreferenceScreen().addPreference(signatureVia);
return true;
} else if (preference.getKey().equalsIgnoreCase("enable_ads")) {
callback.onThemeChanged();
return true;
}
return false;
}
@ -274,7 +271,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);

View File

@ -178,9 +178,15 @@ public class PrettifyWebView extends NestedWebView {
setGithubContent(source, baseUrl, toggleNestScrolling, true);
}
public void setWikiContent(@NonNull String source, @Nullable String baseUrl) {
addJavascriptInterface(new MarkDownInterceptorInterface(this, true), "Android");
String page = GithubHelper.generateContent(getContext(), source, baseUrl, AppHelper.isNightMode(getResources()), true);
post(() -> loadDataWithBaseURL("file:///android_asset/md/", page, "text/html", "utf-8", null));
}
public void setGithubContent(@NonNull String source, @Nullable String baseUrl, boolean toggleNestScrolling, boolean enableBridge) {
if (enableBridge) addJavascriptInterface(new MarkDownInterceptorInterface(this, toggleNestScrolling), "Android");
String page = GithubHelper.generateContent(getContext(), source, baseUrl, AppHelper.isNightMode(getResources()));
String page = GithubHelper.generateContent(getContext(), source, baseUrl, AppHelper.isNightMode(getResources()), false);
post(() -> loadDataWithBaseURL("file:///android_asset/md/", page, "text/html", "utf-8", null));
}

View File

@ -9,27 +9,29 @@ import com.fastaccess.data.dao.NameParser;
import com.fastaccess.helper.PrefGetter;
import com.fastaccess.helper.ViewHelper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Kosh on 25 Dec 2016, 9:12 PM
*/
public class GithubHelper {
private static Pattern LINK_TAG_MATCHER = Pattern.compile("href=\"(.*?)\"");
private static Pattern IMAGE_TAG_MATCHER = Pattern.compile("src=\"(.*?)\"");
@NonNull public static String generateContent(@NonNull Context context, @NonNull String source, @Nullable String baseUrl, boolean dark) {
@NonNull public static String generateContent(@NonNull Context context, @NonNull String source,
@Nullable String baseUrl, boolean dark, boolean isWiki) {
if (baseUrl == null) {
return mergeContent(context, source, dark);
} else {
return mergeContent(context, validateImageBaseUrl(source, baseUrl), dark);
return mergeContent(context, parseReadme(source, baseUrl, isWiki), dark);
}
}
@NonNull private static String validateImageBaseUrl(@NonNull String source, @NonNull String baseUrl) {
@NonNull private static String parseReadme(@NonNull String source, @NonNull String baseUrl, boolean isWiki) {
NameParser nameParser = new NameParser(baseUrl);
String owner = nameParser.getUsername();
String repoName = nameParser.getName();
@ -50,29 +52,48 @@ public class GithubHelper {
builder.append(path).append("/");
}
}
Matcher matcher = IMAGE_TAG_MATCHER.matcher(source);
while (matcher.find()) {
String src = matcher.group(1).trim();
if (src.startsWith("http://") || src.startsWith("https://")) {
continue;
}
String finalSrc;
if (src.startsWith("/" + owner + "/" + repoName)) {
finalSrc = "https://raw.githubusercontent.com/" + src;
} else {
finalSrc = "https://raw.githubusercontent.com/" + builder.toString() + src;
}
source = source.replace("src=\"" + src + "\"", "src=\"" + finalSrc
.replace("raw/", "master/").replaceAll("//", "/") + "\"");
}
return validateLinks(source, baseUrl);
String baseLinkUrl = !isWiki ? getLinkBaseUrl(baseUrl) : baseUrl;
return getParsedHtml(source, owner, repoName, !isWiki ? builder.toString() : baseUrl, baseLinkUrl, isWiki);
}
@NonNull private static String validateLinks(@NonNull String source, @NonNull String baseUrl) {
@NonNull private static String getParsedHtml(@NonNull String source, String owner, String repoName,
String builder, String baseLinkUrl, boolean isWiki) {
Document document = Jsoup.parse(source
.replaceAll("&lt;", "<")
.replaceAll("&gt;", ">"), "");
Elements imageElements = document.getElementsByTag("img");
if (imageElements != null && !imageElements.isEmpty()) {
for (Element element : imageElements) {
String src = element.attr("src");
if (src != null && !(src.startsWith("http://") || src.startsWith("https://"))) {
String finalSrc;
if (src.startsWith("/" + owner + "/" + repoName)) {
finalSrc = "https://raw.githubusercontent.com/" + src;
} else {
finalSrc = "https://raw.githubusercontent.com/" + builder + src;
}
element.attr("src", finalSrc);
}
}
}
Elements linkElements = document.getElementsByTag("a");
if (linkElements != null && !linkElements.isEmpty()) {
for (Element element : linkElements) {
String href = element.attr("href");
if (href.startsWith("#") || href.startsWith("http://") || href.startsWith("https://") || href.startsWith("mailto:")) {
continue;
}
element.attr("href", baseLinkUrl + (isWiki && href.startsWith("wiki")
? href.replaceFirst("wiki", "") : href));
}
}
return document.html();
}
@NonNull private static String getLinkBaseUrl(@NonNull String baseUrl) {
NameParser nameParser = new NameParser(baseUrl);
String owner = nameParser.getUsername();
String repoName = nameParser.getName();
Matcher matcher = LINK_TAG_MATCHER.matcher(source);
Uri uri = Uri.parse(baseUrl);
ArrayList<String> paths = new ArrayList<>(uri.getPathSegments());
StringBuilder builder = new StringBuilder();
@ -88,15 +109,7 @@ public class GithubHelper {
builder.append(path).append("/");
}
}
while (matcher.find()) {
String href = matcher.group(1).trim();
if (href.startsWith("#") || href.startsWith("http://") || href.startsWith("https://") || href.startsWith("mailto:")) {
continue;
}
String link = builder.toString() + "" + href;
source = source.replace("href=\"" + href + "\"", "href=\"" + link + "\"");
}
return source;
return builder.toString();
}
@NonNull private static String mergeContent(@NonNull Context context, @NonNull String source, boolean dark) {