this commit fixes #208 , fixes #206 , fixes #204 , fixes #203 , fixes #202 , fixes #201 (I guess) , fixes #199 and ready to release 1.4.1 with bug fixes and what better, anchor links now works 100% as its done from javascript instead of android.

This commit is contained in:
Kosh 2017-03-27 21:48:35 +08:00
parent c9c0b6cf54
commit 0e6448cb2c
49 changed files with 675 additions and 528 deletions

View File

@ -27,8 +27,8 @@ android {
applicationId "com.fastaccess.github"
minSdkVersion 21
targetSdkVersion 25
versionCode 140
versionName "1.4.0"
versionCode 141
versionName "1.4.1"
signingConfig signingConfigs.signing
buildConfigString "GITHUB_CLIENT_ID", (buildProperties.secrets['github_client_id'] | buildProperties.notThere['github_client_id']).string
buildConfigString "GITHUB_SECRET", (buildProperties.secrets['github_secret'] | buildProperties.notThere['github_secret']).string

View File

@ -1,4 +1,3 @@
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-dontpreverify
-repackageclasses ''

View File

@ -7,6 +7,10 @@ document.addEventListener("DOMContentLoaded", function(event) {
window.onload = function() {
addTouchEvents(document.getElementsByTagName("pre"));
addTouchEvents(document.getElementsByTagName("table"));
var hash = window.location.hash.substr(1);
if (hash != ""){
scrollTo(hash);
}
};
function addTouchEvents(elements) {
@ -23,3 +27,19 @@ function touchStart(event) {
function touchEnd(event) {
Android.stopIntercept();
}
function scrollTo(hash) {
var element = document.getElementById("user-content-" + hash);
element.scrollIntoView();
}
window.onclick = function(e) {
if (e.target.localName == 'a') {
var href = e.target;
href = href.toString().replace("file:///android_asset/md/","");
console.log(href);
if (href.indexOf("#") === 0) {
scrollTo(href.replace("#",""));
}
}
};

View File

@ -133,7 +133,8 @@ public class FragmentPagerAdapterModel {
String login = commitModel.getLogin();
String repoId = commitModel.getRepoId();
String sha = commitModel.getSha();
return Stream.of(new FragmentPagerAdapterModel(context.getString(R.string.commits), CommitFilesView.newInstance(commitModel.getFiles()))
return Stream.of(new FragmentPagerAdapterModel(context.getString(R.string.commits), CommitFilesView.newInstance(commitModel.getSha(),
commitModel.getFiles()))
, new FragmentPagerAdapterModel(context.getString(R.string.comments), CommitCommentsView.newInstance(login, repoId, sha)))
.collect(Collectors.toList());
}

View File

@ -63,71 +63,78 @@ import static com.fastaccess.data.dao.model.Comment.UPDATED_AT;
}
public static Observable saveForGist(@NonNull List<Comment> models, @NonNull String gistId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(GIST_ID.equal(gistId))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(model -> {
model.setGistId(gistId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(GIST_ID.equal(gistId))
.get()
.value();
Stream.of(models)
.forEach(model -> {
model.setGistId(gistId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable saveForCommits(@NonNull List<Comment> models, @NonNull String repoId,
@NonNull String login, @NonNull String commitId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(COMMIT_ID.equal(commitId)
.and(REPO_ID.equal(repoId))
.and(LOGIN.equal(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(model -> {
model.setLogin(login);
model.setRepoId(repoId);
model.setCommitId(commitId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(COMMIT_ID.equal(commitId)
.and(REPO_ID.equal(repoId))
.and(LOGIN.equal(login)))
.get()
.value();
Stream.of(models)
.forEach(model -> {
model.setLogin(login);
model.setRepoId(repoId);
model.setCommitId(commitId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable saveForIssues(@NonNull List<Comment> models, @NonNull String repoId,
@NonNull String login, @NonNull String issueId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(ISSUE_ID.equal(issueId)
.and(REPO_ID.equal(repoId))
.and(LOGIN.equal(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(model -> {
model.setLogin(login);
model.setRepoId(repoId);
model.setIssueId(issueId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(ISSUE_ID.equal(issueId)
.and(REPO_ID.equal(repoId))
.and(LOGIN.equal(login)))
.get()
.value();
Stream.of(models)
.forEach(model -> {
model.setLogin(login);
model.setRepoId(repoId);
model.setIssueId(issueId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable saveForPullRequest(@NonNull List<Comment> models, @NonNull String repoId,
@NonNull String login, @NonNull String pullRequestId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(PULL_REQUEST_ID.equal(pullRequestId)
.and(REPO_ID.equal(repoId))
.and(LOGIN.equal(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(model -> {
model.setLogin(login);
model.setRepoId(repoId);
model.setPullRequestId(pullRequestId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Comment.class)
.where(PULL_REQUEST_ID.equal(pullRequestId)
.and(REPO_ID.equal(repoId))
.and(LOGIN.equal(login)))
.get()
.value();
Stream.of(models)
.forEach(model -> {
model.setLogin(login);
model.setRepoId(repoId);
model.setPullRequestId(pullRequestId);
model.save(model).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<Comment>> getGistComments(@NonNull String gistId) {

View File

@ -65,35 +65,39 @@ public abstract class AbstractCommit implements Parcelable {
}
public static Observable save(@NonNull List<Commit> models, @NonNull String repoId, @NonNull String login) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Commit.class)
.where(REPO_ID.eq(repoId)
.and(LOGIN.eq(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(commitModel -> {
commitModel.setRepoId(repoId);
commitModel.setLogin(login);
commitModel.save(commitModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Commit.class)
.where(REPO_ID.eq(repoId)
.and(LOGIN.eq(login)))
.get()
.value();
Stream.of(models)
.forEach(commitModel -> {
commitModel.setRepoId(repoId);
commitModel.setLogin(login);
commitModel.save(commitModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable save(@NonNull List<Commit> models, @NonNull String repoId, @NonNull String login, long number) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Commit.class)
.where(REPO_ID.eq(repoId)
.and(LOGIN.eq(login))
.and(PULL_REQUEST_NUMBER.eq(number)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(commitModel -> {
commitModel.setRepoId(repoId);
commitModel.setLogin(login);
commitModel.setPullRequestNumber(number);
commitModel.save(commitModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Commit.class)
.where(REPO_ID.eq(repoId)
.and(LOGIN.eq(login))
.and(PULL_REQUEST_NUMBER.eq(number)))
.get()
.value();
Stream.of(models)
.forEach(commitModel -> {
commitModel.setRepoId(repoId);
commitModel.setLogin(login);
commitModel.setPullRequestNumber(number);
commitModel.save(commitModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<Commit>> getCommits(@NonNull String repoId, @NonNull String login) {

View File

@ -67,28 +67,29 @@ import rx.Observable;
}
public static Completable save(@NonNull List<Gist> gists) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
return singleEntityStore.delete(Gist.class)
.where(Gist.OWNER_NAME.isNull())
.get()
.toSingle()
.toCompletable()
.andThen(Observable.from(gists)
.map(gist -> gist.save(gist)))
.toCompletable();
return Completable.fromAction(() -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Gist.class)
.where(Gist.OWNER_NAME.isNull())
.get()
.value();
Stream.of(gists).forEach(gist -> gist.save(gist));
});
}
public static Observable save(@NonNull List<Gist> gists, @NonNull String ownerName) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Gist.class)
.where(Gist.OWNER_NAME.equal(ownerName))
.get()
.value();
return Observable.create(subscriber -> Stream.of(gists)
.forEach(gistsModel -> {
gistsModel.setOwnerName(ownerName);
gistsModel.save(gistsModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Gist.class)
.where(Gist.OWNER_NAME.equal(ownerName))
.get()
.value();
Stream.of(gists)
.forEach(gistsModel -> {
gistsModel.setOwnerName(ownerName);
gistsModel.save(gistsModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}
@NonNull public static Observable<List<Gist>> getMyGists(@NonNull String ownerName) {
@ -140,6 +141,10 @@ import rx.Observable;
}
@NonNull public SpannableBuilder getDisplayTitle(boolean isFromProfile) {
return getDisplayTitle(isFromProfile, false);
}
@NonNull public SpannableBuilder getDisplayTitle(boolean isFromProfile, boolean gistView) {
SpannableBuilder spannableBuilder = SpannableBuilder.builder();
boolean addDescription = true;
if (!isFromProfile) {
@ -150,13 +155,15 @@ import rx.Observable;
} else {
spannableBuilder.bold("Anonymous");
}
List<FilesListModel> files = getFilesAsList();
if (!files.isEmpty()) {
FilesListModel filesListModel = files.get(0);
if (!InputHelper.isEmpty(filesListModel.getFilename()) && filesListModel.getFilename().trim().length() > 2) {
spannableBuilder.append(" ").append("/").append(" ")
.append(filesListModel.getFilename());
addDescription = false;
if (!gistView) {
List<FilesListModel> files = getFilesAsList();
if (!files.isEmpty()) {
FilesListModel filesListModel = files.get(0);
if (!InputHelper.isEmpty(filesListModel.getFilename()) && filesListModel.getFilename().trim().length() > 2) {
spannableBuilder.append(" ").append("/").append(" ")
.append(filesListModel.getFilename());
addDescription = false;
}
}
}
}

View File

@ -79,18 +79,20 @@ import static com.fastaccess.data.dao.model.Issue.UPDATED_AT;
}
public static Observable save(@NonNull List<Issue> models, @NonNull String repoId, @NonNull String login) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Issue.class)
.where(REPO_ID.equal(repoId)
.and(LOGIN.equal(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(issueModel -> {
issueModel.setRepoId(repoId);
issueModel.setLogin(login);
issueModel.save(issueModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Issue.class)
.where(REPO_ID.equal(repoId)
.and(LOGIN.equal(login)))
.get()
.value();
Stream.of(models)
.forEach(issueModel -> {
issueModel.setRepoId(repoId);
issueModel.setLogin(login);
issueModel.save(issueModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<Issue>> getIssues(@NonNull String repoId, @NonNull String login, @NonNull IssueState issueState) {

View File

@ -71,20 +71,22 @@ import static com.fastaccess.data.dao.model.IssueEvent.REPO_ID;
public static Observable save(@NonNull List<IssueEvent> models, @NonNull String repoId,
@NonNull String login, @NonNull String issueId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(IssueEvent.class)
.where(LOGIN.equal(login)
.and(REPO_ID.equal(repoId))
.and(ISSUE_ID.equal(issueId)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(issueEventModel -> {
issueEventModel.setIssueId(issueId);
issueEventModel.setLogin(login);
issueEventModel.setRepoId(repoId);
issueEventModel.save(issueEventModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(IssueEvent.class)
.where(LOGIN.equal(login)
.and(REPO_ID.equal(repoId))
.and(ISSUE_ID.equal(issueId)))
.get()
.value();
Stream.of(models)
.forEach(issueEventModel -> {
issueEventModel.setIssueId(issueId);
issueEventModel.setLogin(login);
issueEventModel.setRepoId(repoId);
issueEventModel.save(issueEventModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<IssueEvent>> get(@NonNull String repoId, @NonNull String login,

View File

@ -50,11 +50,11 @@ import rx.Observable;
}
public static Observable<Object> save(@NonNull List<Notification> models) {
SingleEntityStore<Persistable> dataSource = App.getInstance().getDataStore();
dataSource.delete(Notification.class)
.get()
.value();
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> dataSource = App.getInstance().getDataStore();
dataSource.delete(Notification.class)
.get()
.value();
Stream.of(models).forEach(notification -> notification.save(notification).toObservable().toBlocking().singleOrDefault(null));
subscriber.onCompleted();
});

View File

@ -18,6 +18,7 @@ import com.fastaccess.data.dao.converters.PullRequestConverter;
import com.fastaccess.data.dao.converters.UserConverter;
import com.fastaccess.data.dao.converters.UsersConverter;
import com.fastaccess.data.dao.types.IssueState;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.ParseDateFormat;
import com.fastaccess.ui.widgets.SpannableBuilder;
@ -98,18 +99,20 @@ import static com.fastaccess.data.dao.model.PullRequest.UPDATED_AT;
}
public static Observable save(@NonNull List<PullRequest> models, @NonNull String repoId, @NonNull String login) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(PullRequest.class)
.where(REPO_ID.equal(repoId)
.and(LOGIN.equal(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(pulRequest -> {
pulRequest.setRepoId(repoId);
pulRequest.setLogin(login);
pulRequest.save(pulRequest).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(PullRequest.class)
.where(REPO_ID.equal(repoId)
.and(LOGIN.equal(login)))
.get()
.value();
Stream.of(models)
.forEach(pulRequest -> {
pulRequest.setRepoId(repoId);
pulRequest.setLogin(login);
pulRequest.save(pulRequest).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<PullRequest>> getPullRequests(@NonNull String repoId, @NonNull String login,
@ -144,24 +147,30 @@ import static com.fastaccess.data.dao.model.PullRequest.UPDATED_AT;
}
@NonNull public static SpannableBuilder getMergeBy(@NonNull PullRequest pullRequest, @NonNull Context context) {
boolean isMerge = pullRequest.isMerged();
User merger = (isMerge && pullRequest.getMergedBy() != null) ? pullRequest.getMergedBy() : pullRequest.getUser();
String status = !isMerge ? context.getString(pullRequest.getState().getStatus()) : context.getString(R.string.merged);
SpannableBuilder builder = SpannableBuilder.builder();
builder.bold("#" + pullRequest.getNumber())
.append(" ")
.append(merger.getLogin())
.append(" ")
.append(status)
.append(" ");
boolean isMerge = pullRequest.isMerged() || !InputHelper.isEmpty(pullRequest.mergedAt);
if (isMerge) {
builder.append(ParseDateFormat.getTimeAgo(pullRequest.getMergedAt()));
User merger = pullRequest.getMergedBy();
return SpannableBuilder.builder()
.bold("#" + pullRequest.getNumber())
.append(" ")
.append(merger != null ? merger.getLogin() + " " : "")
.bold(context.getString(R.string.merged))
.append(" ")
.append(ParseDateFormat.getTimeAgo(pullRequest.getMergedAt()));
} else {
builder.append(ParseDateFormat.getTimeAgo(
pullRequest.getState() == IssueState.closed
? pullRequest.getClosedAt() : pullRequest.getCreatedAt()));
User user = pullRequest.getUser();
String status = context.getString(pullRequest.getState().getStatus());
return SpannableBuilder.builder()
.bold("#" + pullRequest.getNumber())
.append(" ")
.append(user.getLogin())
.append(" ")
.bold(status)
.append(" ")
.append(ParseDateFormat.getTimeAgo(
pullRequest.getState() == IssueState.closed
? pullRequest.getClosedAt() : pullRequest.getCreatedAt()));
}
return builder;
}
@Override public int describeContents() { return 0; }

View File

@ -67,17 +67,19 @@ public abstract class AbstractRelease implements Parcelable {
}
public static Observable save(@NonNull List<Release> models, @NonNull String repoId, @NonNull String login) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Release.class)
.where(REPO_ID.eq(login))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(releasesModel -> {
releasesModel.setRepoId(repoId);
releasesModel.setLogin(login);
releasesModel.save(releasesModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Release.class)
.where(REPO_ID.eq(login))
.get()
.value();
Stream.of(models)
.forEach(releasesModel -> {
releasesModel.setRepoId(repoId);
releasesModel.setLogin(login);
releasesModel.save(releasesModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}

View File

@ -141,29 +141,33 @@ import static com.fastaccess.data.dao.model.Repo.UPDATED_AT;
}
public static Observable saveStarred(@NonNull List<Repo> models, @NonNull String starredUser) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Repo.class)
.where(STARRED_USER.eq(starredUser))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(repo -> {
repo.setStarredUser(starredUser);
repo.save(repo).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Repo.class)
.where(STARRED_USER.eq(starredUser))
.get()
.value();
Stream.of(models)
.forEach(repo -> {
repo.setStarredUser(starredUser);
repo.save(repo).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable saveMyRepos(@NonNull List<Repo> models, @NonNull String reposOwner) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Repo.class)
.where(REPOS_OWNER.eq(reposOwner))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(repo -> {
repo.setReposOwner(reposOwner);
repo.save(repo).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(Repo.class)
.where(REPOS_OWNER.eq(reposOwner))
.get()
.value();
Stream.of(models)
.forEach(repo -> {
repo.setReposOwner(reposOwner);
repo.save(repo).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<Repo>> getStarred(@NonNull String starredUser) {

View File

@ -50,18 +50,20 @@ import static com.fastaccess.data.dao.model.RepoFile.TYPE;
}
public static Observable save(@NonNull List<RepoFile> models, @NonNull String login, @NonNull String repoId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(RepoFile.class)
.where(REPO_ID.eq(repoId)
.and(LOGIN.eq(login)))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(filesModel -> {
filesModel.setRepoId(repoId);
filesModel.setLogin(login);
filesModel.save(filesModel).toObservable().toBlocking().singleOrDefault(null);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(RepoFile.class)
.where(REPO_ID.eq(repoId)
.and(LOGIN.eq(login)))
.get()
.value();
Stream.of(models)
.forEach(filesModel -> {
filesModel.setRepoId(repoId);
filesModel.setLogin(login);
filesModel.save(filesModel).toObservable().toBlocking().singleOrDefault(null);
});
});
}
public static Observable<List<RepoFile>> getFiles(@NonNull String login, @NonNull String repoId) {

View File

@ -22,6 +22,11 @@ public abstract class AbstractSearchHistory implements Parcelable {
@Column(unique = true) String text;
public Completable save(SearchHistory entity) {
App.getInstance().getDataStore()
.delete(SearchHistory.class)
.where(SearchHistory.TEXT.eq(entity.getText()))
.get()
.value();
return App.getInstance().getDataStore()
.insert(entity)
.toCompletable();

View File

@ -112,42 +112,48 @@ public abstract class AbstractUser implements Parcelable {
}
public static Observable saveUserFollowerList(@NonNull List<User> models, @NonNull String followingName) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(User.class)
.where(FOLLOWING_NAME.eq(followingName))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(userModel -> {
userModel.setFollowingName(followingName);
userModel.save(userModel);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(User.class)
.where(FOLLOWING_NAME.eq(followingName))
.get()
.value();
Stream.of(models)
.forEach(userModel -> {
userModel.setFollowingName(followingName);
userModel.save(userModel);
});
});
}
public static Observable saveUserFollowingList(@NonNull List<User> models, @NonNull String followerName) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(User.class)
.where(FOLLOWER_NAME.eq(followerName))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(userModel -> {
userModel.setFollowerName(followerName);
userModel.save(userModel);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(User.class)
.where(FOLLOWER_NAME.eq(followerName))
.get()
.value();
Stream.of(models)
.forEach(userModel -> {
userModel.setFollowerName(followerName);
userModel.save(userModel);
});
});
}
public static Observable saveUserContributorList(@NonNull List<User> models, @NonNull String repoId) {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(User.class)
.where(REPO_ID.eq(repoId))
.get()
.value();
return Observable.create(subscriber -> Stream.of(models)
.forEach(userModel -> {
userModel.setRepoId(repoId);
userModel.save(userModel);
}));
return Observable.create(subscriber -> {
SingleEntityStore<Persistable> singleEntityStore = App.getInstance().getDataStore();
singleEntityStore.delete(User.class)
.where(REPO_ID.eq(repoId))
.get()
.value();
Stream.of(models)
.forEach(userModel -> {
userModel.setRepoId(repoId);
userModel.save(userModel);
});
});
}

View File

@ -22,4 +22,8 @@ public class RxHelper {
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread());
}
public static <T> Observable<T> saveObserable(@NonNull Observable<T> observable) {
return getObserver(observable).onErrorReturn(throwable -> null);
}
}

View File

@ -18,8 +18,10 @@ import com.fastaccess.helper.AppHelper;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.PrefGetter;
import com.fastaccess.helper.RxHelper;
import com.fastaccess.helper.ViewHelper;
import com.fastaccess.provider.rest.RestProvider;
import com.fastaccess.ui.modules.notification.NotificationActivityView;
import com.firebase.jobdispatcher.Constraint;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
@ -49,10 +51,9 @@ public class NotificationSchedulerJobTask extends JobService {
.getNotifications(0)
.subscribeOn(Schedulers.io())
.subscribe(item -> {
AppHelper.cancelNotification(this, BundleConstant.REQUEST_CODE);
if (item != null) {
onSave(item.getItems());
} else {
AppHelper.cancelNotification(this, BundleConstant.REQUEST_CODE);
}
}, Throwable::printStackTrace);
}
@ -90,7 +91,7 @@ public class NotificationSchedulerJobTask extends JobService {
private void onSave(@Nullable List<Notification> notificationThreadModels) {
if (notificationThreadModels != null) {
Notification.save(notificationThreadModels).subscribe();
RxHelper.saveObserable(Notification.save(notificationThreadModels)).subscribe();
onNotifyUser(notificationThreadModels);
}
}
@ -106,17 +107,22 @@ public class NotificationSchedulerJobTask extends JobService {
Context context = getApplicationContext();
Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(),
R.mipmap.ic_launcher);
int primaryColor = ViewHelper.getPrimaryColor(context);
android.app.Notification grouped = getNotification(getString(R.string.notifications), getString(R.string.unread_notification))
Intent intent = new Intent(this, NotificationActivityView.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
int accentColor = ViewHelper.getAccentColor(context);
android.app.Notification grouped = getNotification(getString(R.string.app_name), getString(R.string.notifications_hint))
.setLargeIcon(largeIcon)
.setGroup(NOTIFICATION_GROUP_ID)
.setGroupSummary(true)
.setColor(primaryColor)
.setColor(accentColor)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
showNotification(BundleConstant.REQUEST_CODE, grouped);
Stream.of(notificationThreadModels)
.filter(Notification::isUnread)
.limit(10)
.forEach(thread -> {
if (!InputHelper.isEmpty(thread.getSubject().getLatestCommentUrl())) {
RestProvider.getNotificationService().getComment(thread.getSubject().getLatestCommentUrl())
@ -130,7 +136,7 @@ public class NotificationSchedulerJobTask extends JobService {
.setLargeIcon(largeIcon)
.setContentIntent(getPendingIntent(thread.getId(), thread.getSubject().getUrl()))
.setGroup(NOTIFICATION_GROUP_ID)
.setColor(primaryColor)
.setColor(accentColor)
.addAction(R.drawable.ic_github, context.getString(R.string.open), getPendingIntent(thread.getId(),
thread.getSubject().getUrl()))
.build();
@ -142,7 +148,7 @@ public class NotificationSchedulerJobTask extends JobService {
.setLargeIcon(largeIcon)
.setContentIntent(getPendingIntent(thread.getId(), thread.getSubject().getUrl()))
.setGroup(NOTIFICATION_GROUP_ID)
.setColor(primaryColor)
.setColor(accentColor)
.addAction(R.drawable.ic_github, context.getString(R.string.open), getPendingIntent(thread.getId(), thread
.getSubject().getUrl()))
.build();

View File

@ -43,9 +43,9 @@ public class GistsViewHolder extends BaseViewHolder<Gist> {
@Override public void bind(@NonNull Gist item) {
if (!isFromProfile) {
String url = item.getOwner() != null ? item.getOwner().getAvatarUrl() : item.getUser() != null ? item.getUser().getAvatarUrl() : null;
String login = item.getOwner() != null ? item.getOwner().getLogin() : item.getUser() != null ? item.getUser().getLogin() : null;
if (avatar != null) {
String url = item.getOwner() != null ? item.getOwner().getAvatarUrl() : item.getUser() != null ? item.getUser().getAvatarUrl() : null;
String login = item.getOwner() != null ? item.getOwner().getLogin() : item.getUser() != null ? item.getUser().getLogin() : null;
avatar.setUrl(url, login);
}
}

View File

@ -1,6 +1,5 @@
package com.fastaccess.ui.modules.changelog;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -47,7 +46,6 @@ public class ChangelogView extends BaseBottomSheetDialog {
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
messageLayout.setBackgroundColor(Color.WHITE);
if (savedInstanceState == null) {
PrefGetter.setWhatsNewVersion();
}

View File

@ -138,7 +138,7 @@ public class EditorView extends BaseActivity<EditorMvp.View, EditorPresenter> im
hideProgress();
Intent intent = new Intent();
intent.putExtras(Bundler.start()
.put(BundleConstant.ITEM, commentModel)
// .put(BundleConstant.ITEM, commentModel)
.put(BundleConstant.EXTRA, isNew)
.end());
setResult(RESULT_OK, intent);

View File

@ -200,7 +200,7 @@ public class GistView extends BaseActivity<GistMvp.View, GistPresenter>
String login = gistsModel.getOwner() != null ? gistsModel.getOwner().getLogin() :
gistsModel.getUser() != null ? gistsModel.getUser().getLogin() : "";
avatarLayout.setUrl(url, login);
title.setText(gistsModel.getDisplayTitle(false));
title.setText(gistsModel.getDisplayTitle(false, true));
detailsIcon.setVisibility(InputHelper.isEmpty(gistsModel.getDescription()) || !ViewHelper.isEllipsed(title) ? View.GONE : View.VISIBLE);
date.setText(ParseDateFormat.getTimeAgo(gistsModel.getCreatedAt()));
size.setText(Formatter.formatFileSize(this, gistsModel.getSize()));

View File

@ -69,10 +69,8 @@ public class DonationView extends BaseDialogFragment<DonationMvp.View, DonationP
subscription = getPago().purchaseProduct(productKey, item)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(order -> {
showMessage(R.string.success, R.string.success_purchase_message);
dismiss();
}, throwable -> showErrorMessage(throwable.getMessage()));
.subscribe(order -> showMessage(R.string.success, R.string.success_purchase_message),
throwable -> showErrorMessage(throwable.getMessage()));
}
@Override public void onItemLongClick(int position, View v, String item) {

View File

@ -8,8 +8,6 @@ import com.fastaccess.data.dao.PullsIssuesParser;
import com.fastaccess.data.dao.model.Issue;
import com.fastaccess.data.dao.model.Login;
import com.fastaccess.data.dao.types.IssueState;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.Logger;
import com.fastaccess.provider.rest.RepoQueryProvider;
import com.fastaccess.provider.rest.RestProvider;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
@ -29,7 +27,6 @@ public class MyIssuesPresenter extends BasePresenter<MyIssuesMvp.View> implement
private int lastPage = Integer.MAX_VALUE;
@Override public void onItemClick(int position, View v, Issue item) {
Logger.e(Bundler.start().put("item", item).end().size());
PullsIssuesParser parser = PullsIssuesParser.getForIssue(item.getHtmlUrl());
if (parser != null) {
v.getContext().startActivity(IssuePagerView.createIntent(v.getContext(), parser.getRepoId(),

View File

@ -9,8 +9,6 @@ import com.fastaccess.data.dao.PullsIssuesParser;
import com.fastaccess.data.dao.model.Login;
import com.fastaccess.data.dao.model.PullRequest;
import com.fastaccess.data.dao.types.IssueState;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.Logger;
import com.fastaccess.provider.rest.RepoQueryProvider;
import com.fastaccess.provider.rest.RestProvider;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
@ -30,7 +28,6 @@ public class MyPullRequestsPresenter extends BasePresenter<MyPullRequestsMvp.Vie
private int lastPage = Integer.MAX_VALUE;
@Override public void onItemClick(int position, View v, PullRequest item) {
Logger.e(Bundler.start().put("item", item).end().size());
PullsIssuesParser parser = PullsIssuesParser.getForPullRequest(item.getHtmlUrl());
if (parser != null) {
Intent intent = PullRequestPagerView.createIntent(v.getContext(), parser.getRepoId(), parser.getLogin(), parser.getNumber(), true);

View File

@ -11,11 +11,9 @@ import android.widget.Button;
import com.fastaccess.R;
import com.fastaccess.data.dao.model.Login;
import com.fastaccess.data.dao.model.User;
import com.fastaccess.helper.AnimHelper;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.Logger;
import com.fastaccess.helper.ParseDateFormat;
import com.fastaccess.ui.base.BaseFragment;
import com.fastaccess.ui.modules.profile.ProfilePagerMvp;
@ -63,7 +61,7 @@ public class ProfileOverviewView extends BaseFragment<ProfileOverviewMvp.View, P
profileCallback.onNavigateToFollowing();
} else if (view.getId() == R.id.followBtn) {
getPresenter().onFollowButtonClicked(getPresenter().getLogin());
AnimHelper.animateVisibility(followBtn, false, View.INVISIBLE);
followBtn.setEnabled(false);
}
}
@ -132,18 +130,9 @@ public class ProfileOverviewView extends BaseFragment<ProfileOverviewMvp.View, P
hideProgress();
if (isMeOrOrganization()) return;
if (getPresenter().isSuccessResponse()) {
AnimHelper.animateVisibility(followBtn, true, View.INVISIBLE, new AnimHelper.AnimationCallback() {
@Override public void onAnimationEnd() {
followBtn.setActivated(getPresenter().isFollowing());
}
@Override public void onAnimationStart() {
if (followBtn == null) return;
Logger.e(getPresenter().isFollowing());
followBtn.setText(getPresenter().isFollowing() ? getString(R.string.unfollow) : getString(R.string.follow));
}
});
followBtn.setEnabled(true);
followBtn.setActivated(getPresenter().isFollowing());
followBtn.setText(getPresenter().isFollowing() ? getString(R.string.unfollow) : getString(R.string.follow));
}
}

View File

@ -66,6 +66,8 @@ public interface RepoPagerMvp {
interface Presenter extends BaseMvp.FAPresenter, BottomNavigation.OnMenuItemSelectionListener {
void onActivityCreate(@NonNull String repoId, @NonNull String login, @RepoPagerMvp.RepoNavigationType int navTyp);
@NonNull String repoId();
@NonNull String login();

View File

@ -30,19 +30,12 @@ class RepoPagerPresenter extends BasePresenter<RepoPagerMvp.View> implements Rep
private boolean isWatched;
private boolean isStarred;
private boolean isForked;
private final String login;
private final String repoId;
private String login;
private String repoId;
private Repo repo;
private int navTyp;
RepoPagerPresenter(final String repoId, final String login, @RepoPagerMvp.RepoNavigationType int navTyp) {
if (!InputHelper.isEmpty(login) && !InputHelper.isEmpty(repoId())) {
throw new IllegalArgumentException("arguments cannot be empty");
}
this.repoId = repoId;
this.login = login;
this.navTyp = navTyp;
}
RepoPagerPresenter() {}
private void callApi(int navTyp) {
if (InputHelper.isEmpty(login) || InputHelper.isEmpty(repoId)) return;
@ -64,12 +57,14 @@ class RepoPagerPresenter extends BasePresenter<RepoPagerMvp.View> implements Rep
super.onError(throwable);
}
@Override protected void onAttachView(final @NonNull RepoPagerMvp.View view) {
super.onAttachView(view);
if (getRepo() != null) {
view.onInitRepo();
} else {
@Override public void onActivityCreate(@NonNull String repoId, @NonNull String login, int navTyp) {
this.login = login;
this.repoId = repoId;
this.navTyp = navTyp;
if (getRepo() == null || !isApiCalled()) {
callApi(navTyp);
} else {
sendToView(RepoPagerMvp.View::onInitRepo);
}
}

View File

@ -17,6 +17,7 @@ import android.view.View;
import android.widget.LinearLayout;
import com.fastaccess.R;
import com.fastaccess.data.dao.LicenseModel;
import com.fastaccess.data.dao.NameParser;
import com.fastaccess.data.dao.model.AbstractPinnedRepos;
import com.fastaccess.data.dao.model.Repo;
@ -180,21 +181,18 @@ public class RepoPagerView extends BaseActivity<RepoPagerMvp.View, RepoPagerPres
}
@NonNull @Override public RepoPagerPresenter providePresenter() {
if (getIntent() == null) {
throw new IllegalArgumentException("intent is null, WTF");
}
if (getIntent().getExtras() == null) {
throw new IllegalArgumentException("no intent extras provided");
}
final Bundle extras = getIntent().getExtras();
repoId = extras.getString(BundleConstant.ID);
login = extras.getString(BundleConstant.EXTRA_TWO);
navType = extras.getInt(BundleConstant.EXTRA_TYPE);
return new RepoPagerPresenter(repoId, login, navType);
return new RepoPagerPresenter();
}
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final Bundle extras = getIntent().getExtras();
repoId = extras.getString(BundleConstant.ID);
login = extras.getString(BundleConstant.EXTRA_TWO);
navType = extras.getInt(BundleConstant.EXTRA_TYPE);
}
getPresenter().onActivityCreate(repoId, login, navType);
setTitle("");
accentColor = ViewHelper.getAccentColor(this);
iconColor = ViewHelper.getIconColor(this);
@ -249,9 +247,10 @@ public class RepoPagerView extends BaseActivity<RepoPagerMvp.View, RepoPagerPres
title.setText(repoModel.getFullName());
TextViewCompat.setTextAppearance(title, R.style.TextAppearance_AppCompat_Medium);
title.setTextColor(ViewHelper.getPrimaryTextColor(this));
if (!InputHelper.isEmpty(repoModel.getLicense())) {
if (repoModel.getLicense() != null) {
licenseLayout.setVisibility(View.VISIBLE);
license.setText(repoModel.getLicense().getSpdxId());
LicenseModel licenseModel = repoModel.getLicense();
license.setText(!InputHelper.isEmpty(licenseModel.getSpdxId()) ? licenseModel.getSpdxId() : licenseModel.getName());
}
supportInvalidateOptionsMenu();
if (!PrefGetter.isRepoGuideShowed()) {// the mother of nesting. #dontjudgeme.

View File

@ -98,11 +98,6 @@ public class CommitCommentsView extends BaseFragment<CommitCommentsMvp.View, Com
super.showMessage(titleRes, msgRes);
}
private void showReload() {
hideProgress();
stateLayout.showReload(adapter.getItemCount());
}
@NonNull @Override public CommitCommentsPresenter providePresenter() {
return new CommitCommentsPresenter();
}
@ -191,4 +186,9 @@ public class CommitCommentsView extends BaseFragment<CommitCommentsMvp.View, Com
getPresenter().onHandleDeletion(bundle);
}
}
private void showReload() {
hideProgress();
stateLayout.showReload(adapter.getItemCount());
}
}

View File

@ -8,6 +8,7 @@ import android.view.View;
import com.fastaccess.data.dao.CommitFileListModel;
import com.fastaccess.data.dao.CommitFileModel;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
/**
@ -19,7 +20,7 @@ class CommitFilesPresenter extends BasePresenter<CommitFilesMvp.View> implements
private CommitFileListModel files = new CommitFileListModel();
@Override public void onItemClick(int position, View v, CommitFileModel item) {
}
@Override public void onItemLongClick(int position, View v, CommitFileModel item) {
@ -28,9 +29,13 @@ class CommitFilesPresenter extends BasePresenter<CommitFilesMvp.View> implements
@Override public void onFragmentCreated(@Nullable Bundle bundle) {
if (bundle != null) {
CommitFileListModel files = (CommitFileListModel) bundle.get(BundleConstant.EXTRA);
if (files != null) {
this.files.addAll(files);
String sha = bundle.getString(BundleConstant.ID);
if (!InputHelper.isEmpty(sha)) {
CommitFileListModel commitFiles = CommitFilesSingleton.getInstance().getByCommitId(sha);
if (commitFiles != null) {
this.files.addAll(commitFiles);
CommitFilesSingleton.getInstance().clear();
}
}
sendToView(CommitFilesMvp.View::onNotifyAdapter);
} else {

View File

@ -0,0 +1,39 @@
package com.fastaccess.ui.modules.repos.code.commit.details.files;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.fastaccess.data.dao.CommitFileListModel;
import java.util.Hashtable;
import java.util.Map;
/**
* Created by Kosh on 27 Mar 2017, 7:28 PM
*/
class CommitFilesSingleton {
private static final CommitFilesSingleton ourInstance = new CommitFilesSingleton();
static CommitFilesSingleton getInstance() {
return ourInstance;
}
private Map<String, CommitFileListModel> files = new Hashtable<>();
private CommitFilesSingleton() {
}
void putFiles(@NonNull String id, @NonNull CommitFileListModel commitFiles) {
files.clear();
files.put(id, commitFiles);
}
@Nullable CommitFileListModel getByCommitId(@NonNull String id) {
return files.get(id);
}
void clear() {
files.clear();
}
}

View File

@ -33,11 +33,13 @@ public class CommitFilesView extends BaseFragment<CommitFilesMvp.View, CommitFil
private CommitFilesAdapter adapter;
public static CommitFilesView newInstance(@Nullable CommitFileListModel commitFileModels) {
public static CommitFilesView newInstance(@NonNull String sha, @Nullable CommitFileListModel commitFileModels) {//TODO fix this
CommitFilesView view = new CommitFilesView();
view.setArguments(Bundler.start()
.putParcelableArrayList(BundleConstant.EXTRA, commitFileModels)
.end());
if (commitFileModels != null) {
CommitFilesSingleton.getInstance().putFiles(sha, commitFileModels);
}
Bundle bundle = Bundler.start().put(BundleConstant.ID, sha).end();
view.setArguments(bundle);
return view;
}

View File

@ -62,7 +62,7 @@ public class CreateIssueView extends BaseActivity<CreateIssueMvp.View, CreateIss
intent.putExtras(Bundler.start()
.put(BundleConstant.EXTRA, login)
.put(BundleConstant.ID, repoId)
.put(BundleConstant.ITEM, issueModel)
.put(BundleConstant.ITEM, issueModel)//TODO remove this pass only required data.
.end());
activity.startActivityForResult(intent, BundleConstant.REQUEST_CODE);
}
@ -75,7 +75,7 @@ public class CreateIssueView extends BaseActivity<CreateIssueMvp.View, CreateIss
intent.putExtras(Bundler.start()
.put(BundleConstant.EXTRA, login)
.put(BundleConstant.ID, repoId)
.put(BundleConstant.ITEM, pullRequestModel)
.put(BundleConstant.ITEM, pullRequestModel)//TODO remove this, pass only required data
.end());
activity.startActivityForResult(intent, BundleConstant.REQUEST_CODE);
}

View File

@ -56,10 +56,9 @@ public class RepoClosedIssuesView extends BaseFragment<RepoIssuesMvp.View, RepoI
super.onDetach();
}
@Override public void onNotifyAdapter(int totalCount) {
@Override public void onNotifyAdapter() {
hideProgress();
adapter.notifyDataSetChanged();
if (tabsBadgeListener != null) tabsBadgeListener.onSetBadge(1, totalCount);
}
@Override protected int fragmentLayout() {
@ -126,8 +125,12 @@ public class RepoClosedIssuesView extends BaseFragment<RepoIssuesMvp.View, RepoI
//DO NOTHING
}
@Override public void onUpdateCount(int totalCount) {
if (tabsBadgeListener != null) tabsBadgeListener.onSetBadge(1, totalCount);
}
@Override public void onRefresh() {
getPresenter().onCallApi(1, null);
getPresenter().onCallApi(1, IssueState.closed);
}
@Override public void onClick(View view) {

View File

@ -19,11 +19,13 @@ import java.util.ArrayList;
interface RepoIssuesMvp {
interface View extends BaseMvp.FAView, SwipeRefreshLayout.OnRefreshListener, android.view.View.OnClickListener {
void onNotifyAdapter(int totalCount);
void onNotifyAdapter();
@NonNull OnLoadMore<IssueState> getLoadMore();
void onAddIssue();
void onUpdateCount(int totalCount);
}
interface Presenter extends BaseMvp.FAPresenter,

View File

@ -9,7 +9,6 @@ import com.fastaccess.data.dao.PullsIssuesParser;
import com.fastaccess.data.dao.model.Issue;
import com.fastaccess.data.dao.types.IssueState;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.Logger;
import com.fastaccess.helper.RxHelper;
@ -57,6 +56,11 @@ class RepoIssuesPresenter extends BasePresenter<RepoIssuesMvp.View> implements R
}
@Override public void onCallApi(int page, @Nullable IssueState parameter) {
if (parameter == null) {
sendToView(RepoIssuesMvp.View::hideProgress);
return;
}
this.issueState = parameter;
Logger.e(page, page, login, repoId);
if (page == 1) {
lastPage = Integer.MAX_VALUE;
@ -67,8 +71,7 @@ class RepoIssuesPresenter extends BasePresenter<RepoIssuesMvp.View> implements R
return;
}
setCurrentPage(page);
makeRestCall(RestProvider.getIssueService().getIssuesWithCount(RepoQueryProvider
.getIssuesPullRequerQuery(login, repoId, issueState, false), page),
makeRestCall(RestProvider.getIssueService().getRepositoryIssues(login, repoId, parameter.name(), page),
issues -> {
lastPage = issues.getLast();
if (getCurrentPage() == 1) {
@ -76,16 +79,24 @@ class RepoIssuesPresenter extends BasePresenter<RepoIssuesMvp.View> implements R
manageSubscription(Issue.save(issues.getItems(), repoId, login).subscribe());
}
getIssues().addAll(issues.getItems());
sendToView(view -> view.onNotifyAdapter(issues.getTotalCount()));
sendToView(RepoIssuesMvp.View::onNotifyAdapter);
});
}
private void onCallCountApi(@NonNull IssueState issueState) {
manageSubscription(RxHelper.getObserver(RestProvider.getIssueService()
.getIssuesWithCount(RepoQueryProvider.getIssuesPullRequerQuery(login, repoId, issueState, false), 1))
.subscribe(pullRequestPageable -> sendToView(view -> view.onUpdateCount(pullRequestPageable.getTotalCount())),
Throwable::printStackTrace));
}
@Override public void onFragmentCreated(@NonNull Bundle bundle, @NonNull IssueState issueState) {
repoId = bundle.getString(BundleConstant.ID);
login = bundle.getString(BundleConstant.EXTRA);
this.issueState = issueState;
if (!InputHelper.isEmpty(login) && !InputHelper.isEmpty(repoId)) {
onCallApi(1, null);
onCallApi(1, issueState);
onCallCountApi(issueState);
}
}
@ -94,7 +105,10 @@ class RepoIssuesPresenter extends BasePresenter<RepoIssuesMvp.View> implements R
manageSubscription(RxHelper.getObserver(Issue.getIssues(repoId, login, issueState))
.subscribe(issueModel -> {
issues.addAll(issueModel);
sendToView(view -> view.onNotifyAdapter(issues.size()));
sendToView(view -> {
view.onNotifyAdapter();
view.onUpdateCount(issues.size());
});
}));
} else {
sendToView(BaseMvp.FAView::hideProgress);
@ -114,7 +128,6 @@ class RepoIssuesPresenter extends BasePresenter<RepoIssuesMvp.View> implements R
}
@Override public void onItemClick(int position, View v, Issue item) {
Logger.e(Bundler.start().put("item", item).end().size());
PullsIssuesParser parser = PullsIssuesParser.getForIssue(item.getHtmlUrl());
if (parser != null) {
v.getContext().startActivity(IssuePagerView.createIntent(v.getContext(), parser.getRepoId(),

View File

@ -67,8 +67,7 @@ public class RepoOpenedIssuesView extends BaseFragment<RepoIssuesMvp.View, RepoI
super.onDetach();
}
@Override public void onNotifyAdapter(int totalCount) {
if (tabsBadgeListener != null) tabsBadgeListener.onSetBadge(0, totalCount);
@Override public void onNotifyAdapter() {
hideProgress();
adapter.notifyDataSetChanged();
}
@ -129,11 +128,6 @@ public class RepoOpenedIssuesView extends BaseFragment<RepoIssuesMvp.View, RepoI
super.showMessage(titleRes, msgRes);
}
private void showReload() {
hideProgress();
stateLayout.showReload(adapter.getItemCount());
}
@NonNull @Override public OnLoadMore<IssueState> getLoadMore() {
if (onLoadMore == null) {
onLoadMore = new OnLoadMore<>(getPresenter());
@ -146,11 +140,20 @@ public class RepoOpenedIssuesView extends BaseFragment<RepoIssuesMvp.View, RepoI
CreateIssueView.startForResult(this, getPresenter().login(), getPresenter().repoId());
}
@Override public void onUpdateCount(int totalCount) {
if (tabsBadgeListener != null) tabsBadgeListener.onSetBadge(0, totalCount);
}
@Override public void onRefresh() {
getPresenter().onCallApi(1, null);
getPresenter().onCallApi(1, IssueState.open);
}
@Override public void onClick(View view) {
onRefresh();
}
private void showReload() {
hideProgress();
stateLayout.showReload(adapter.getItemCount());
}
}

View File

@ -32,7 +32,7 @@ public class IssueDetailsView extends BaseFragment<IssueDetailsMvp.View, IssueDe
public static IssueDetailsView newInstance(@NonNull Issue issueModel) {
IssueDetailsView view = new IssueDetailsView();
view.setArguments(Bundler.start().put(BundleConstant.ITEM, issueModel).end());
view.setArguments(Bundler.start().put(BundleConstant.ITEM, issueModel).end());//TODO fix this
return view;
}

View File

@ -19,9 +19,11 @@ import java.util.ArrayList;
interface RepoPullRequestMvp {
interface View extends BaseMvp.FAView, SwipeRefreshLayout.OnRefreshListener, android.view.View.OnClickListener {
void onNotifyAdapter(int totalCount);
void onNotifyAdapter();
@NonNull OnLoadMore<IssueState> getLoadMore();
void onUpdateCount(int totalCount);
}
interface Presenter extends BaseMvp.FAPresenter,

View File

@ -10,9 +10,7 @@ import com.fastaccess.data.dao.PullsIssuesParser;
import com.fastaccess.data.dao.model.PullRequest;
import com.fastaccess.data.dao.types.IssueState;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.Logger;
import com.fastaccess.helper.RxHelper;
import com.fastaccess.provider.rest.RepoQueryProvider;
import com.fastaccess.provider.rest.RestProvider;
@ -58,6 +56,11 @@ class RepoPullRequestPresenter extends BasePresenter<RepoPullRequestMvp.View> im
}
@Override public void onCallApi(int page, @Nullable IssueState parameter) {
if (parameter == null) {
sendToView(RepoPullRequestMvp.View::hideProgress);
return;
}
this.issueState = parameter;
if (page == 1) {
lastPage = Integer.MAX_VALUE;
sendToView(view -> view.getLoadMore().reset());
@ -68,15 +71,14 @@ class RepoPullRequestPresenter extends BasePresenter<RepoPullRequestMvp.View> im
return;
}
if (repoId == null || login == null) return;
makeRestCall(RestProvider.getPullRequestSerice().getPullsWithCount(RepoQueryProvider.getIssuesPullRequerQuery(login, repoId, issueState,
true), page), response -> {
makeRestCall(RestProvider.getPullRequestSerice().getPullRequests(login, repoId, parameter.name(), page), response -> {
lastPage = response.getLast();
if (getCurrentPage() == 1) {
getPullRequests().clear();
manageSubscription(PullRequest.save(response.getItems(), login, repoId).subscribe());
}
getPullRequests().addAll(response.getItems());
sendToView(view -> view.onNotifyAdapter(response.getTotalCount()));
sendToView(RepoPullRequestMvp.View::onNotifyAdapter);
});
}
@ -85,16 +87,27 @@ class RepoPullRequestPresenter extends BasePresenter<RepoPullRequestMvp.View> im
login = bundle.getString(BundleConstant.EXTRA);
issueState = (IssueState) bundle.getSerializable(BundleConstant.EXTRA_TWO);
if (!InputHelper.isEmpty(login) && !InputHelper.isEmpty(repoId)) {
onCallApi(1, null);
onCallApi(1, issueState);
onCallCountApi(issueState);
}
}
private void onCallCountApi(@NonNull IssueState issueState) {
manageSubscription(RxHelper.getObserver(RestProvider.getPullRequestSerice()
.getPullsWithCount(RepoQueryProvider.getIssuesPullRequerQuery(login, repoId, issueState, true), 0))
.subscribe(pullRequestPageable -> sendToView(view -> view.onUpdateCount(pullRequestPageable.getTotalCount())),
Throwable::printStackTrace));
}
@Override public void onWorkOffline() {
if (pullRequests.isEmpty()) {
manageSubscription(RxHelper.getObserver(PullRequest.getPullRequests(repoId, login, issueState))
.subscribe(pulls -> {
pullRequests.addAll(pulls);
sendToView(view -> view.onNotifyAdapter(pullRequests.size()));
sendToView(view -> {
view.onNotifyAdapter();
view.onUpdateCount(pullRequests.size());
});
}));
} else {
sendToView(BaseMvp.FAView::hideProgress);
@ -110,7 +123,6 @@ class RepoPullRequestPresenter extends BasePresenter<RepoPullRequestMvp.View> im
}
@Override public void onItemClick(int position, View v, PullRequest item) {
Logger.e(Bundler.start().put("item", item).end().size());
PullsIssuesParser parser = PullsIssuesParser.getForPullRequest(item.getHtmlUrl());
if (parser != null) {
Intent intent = PullRequestPagerView.createIntent(v.getContext(), parser.getRepoId(), parser.getLogin(), parser.getNumber());

View File

@ -12,7 +12,6 @@ import com.fastaccess.R;
import com.fastaccess.data.dao.types.IssueState;
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.ui.adapter.PullRequestAdapter;
import com.fastaccess.ui.base.BaseFragment;
@ -58,9 +57,7 @@ public class RepoPullRequestView extends BaseFragment<RepoPullRequestMvp.View, R
super.onDetach();
}
@Override public void onNotifyAdapter(int totalCount) {
if (tabsBadgeListener != null) tabsBadgeListener.onSetBadge(getPresenter().getIssueState() == IssueState.open ? 0 : 1, totalCount);
Logger.e();
@Override public void onNotifyAdapter() {
hideProgress();
adapter.notifyDataSetChanged();
}
@ -73,8 +70,6 @@ public class RepoPullRequestView extends BaseFragment<RepoPullRequestMvp.View, R
if (getArguments() == null) {
throw new NullPointerException("Bundle is null, therefore, issues can't be proceeded.");
}
stateLayout.setEmptyText(getPresenter().getIssueState() == IssueState.open
? R.string.no_open_pull_requests : R.string.no_closed_pull_request);
stateLayout.setOnReloadListener(this);
refresh.setOnRefreshListener(this);
recycler.setEmptyView(stateLayout, refresh);
@ -88,6 +83,8 @@ public class RepoPullRequestView extends BaseFragment<RepoPullRequestMvp.View, R
} else if (getPresenter().getPullRequests().isEmpty() && !getPresenter().isApiCalled()) {
onRefresh();
}
stateLayout.setEmptyText(getPresenter().getIssueState() == IssueState.open
? R.string.no_open_pull_requests : R.string.no_closed_pull_request);
}
@NonNull @Override public RepoPullRequestPresenter providePresenter() {
@ -114,23 +111,32 @@ public class RepoPullRequestView extends BaseFragment<RepoPullRequestMvp.View, R
super.showMessage(titleRes, msgRes);
}
private void showReload() {
hideProgress();
stateLayout.showReload(adapter.getItemCount());
}
@NonNull @Override public OnLoadMore<IssueState> getLoadMore() {
if (onLoadMore == null) {
onLoadMore = new OnLoadMore<>(getPresenter());
}
onLoadMore.setParameter(getIssueState());
return onLoadMore;
}
@Override public void onUpdateCount(int totalCount) {
if (tabsBadgeListener != null) tabsBadgeListener.onSetBadge(getPresenter().getIssueState() == IssueState.open ? 0 : 1, totalCount);
}
@Override public void onRefresh() {
getPresenter().onCallApi(1, null);
getPresenter().onCallApi(1, getIssueState());
}
@Override public void onClick(View view) {
onRefresh();
}
private IssueState getIssueState() {
return ((IssueState) getArguments().getSerializable(BundleConstant.EXTRA_TWO));
}
private void showReload() {
hideProgress();
stateLayout.showReload(adapter.getItemCount());
}
}

View File

@ -33,7 +33,7 @@ public class PullRequestDetailsView extends BaseFragment<PullRequestDetailsMvp.V
public static PullRequestDetailsView newInstance(@NonNull PullRequest issueModel) {
PullRequestDetailsView view = new PullRequestDetailsView();
view.setArguments(Bundler.start().put(BundleConstant.ITEM, issueModel).end());
view.setArguments(Bundler.start().put(BundleConstant.ITEM, issueModel).end());//TODO fix this
return view;
}

View File

@ -162,9 +162,7 @@ public class PrettifyWebView extends NestedWebView {
CodeViewerView.startActivity(getContext(), url.toString());
} else {
String anchorLink = url.getEncodedFragment();
Logger.e(anchorLink);
if (anchorLink != null) {
loadUrl("javascript:scrollTo(\"" + anchorLink + "\")");
if (anchorLink != null && anchorLink.startsWith("#")) {
return;
}
SchemeParser.launchUri(getContext(), url, true);

View File

@ -12,8 +12,8 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:clipToPadding="false">
android:clipToPadding="false"
android:fillViewport="true">
<com.fastaccess.ui.widgets.FontEditText
android:id="@+id/editText"
@ -22,7 +22,7 @@
android:background="@color/transparent"
android:gravity="top|start"
android:hint="@string/type_here"
android:inputType="textMultiLine"
android:inputType="textMultiLine|textCapSentences"
android:minLines="5"
android:padding="@dimen/spacing_xs_large"
android:scrollbars="vertical"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
@ -12,137 +12,143 @@
tools:showIn="@layout/header_title_with_toolbar">
<LinearLayout
android:id="@+id/watchRepoLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
android:orientation="horizontal">
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/watchRepoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_eye"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/watchRepo"
style="@style/TextAppearance.AppCompat.Small"
<LinearLayout
android:id="@+id/watchRepoLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
tools:text="100,000"/>
android:orientation="vertical">
</LinearLayout>
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/watchRepoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_eye"/>
<LinearLayout
android:id="@+id/starRepoLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:orientation="vertical">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/watchRepo"
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
tools:text="100,000"/>
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/starRepoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_star"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/starRepo"
style="@style/TextAppearance.AppCompat.Small"
</LinearLayout>
<LinearLayout
android:id="@+id/starRepoLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
tools:text="100,000"/>
android:orientation="vertical">
</LinearLayout>
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/starRepoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_star"/>
<LinearLayout
android:id="@+id/forkRepoLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:orientation="vertical">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/starRepo"
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
tools:text="100,000"/>
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/forkRepoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_fork"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/forkRepo"
style="@style/TextAppearance.AppCompat.Small"
</LinearLayout>
<LinearLayout
android:id="@+id/forkRepoLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
tools:text="100,000"/>
android:orientation="vertical">
</LinearLayout>
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/forkRepoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_fork"/>
<LinearLayout
android:id="@+id/licenseLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/forkRepo"
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
tools:text="100,000"/>
<com.fastaccess.ui.widgets.ForegroundImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/mal_title_licenses"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_license"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/license"
style="@style/TextAppearance.AppCompat.Small"
</LinearLayout>
<LinearLayout
android:id="@+id/licenseLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:maxLength="6"
android:maxLines="1"
tools:text="Apache"/>
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
</LinearLayout>
<com.fastaccess.ui.widgets.ForegroundImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/mal_title_licenses"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_license"/>
<LinearLayout
android:id="@+id/pinLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:orientation="vertical">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/license"
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLength="6"
android:maxLines="1"
tools:text="Apache"/>
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/pinImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_pin"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/pinText"
style="@style/TextAppearance.AppCompat.Small"
</LinearLayout>
<LinearLayout
android:id="@+id/pinLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:text="@string/pin"/>
android:orientation="vertical">
<com.fastaccess.ui.widgets.ForegroundImageView
android:id="@+id/pinImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_normal"
android:src="@drawable/ic_pin"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/pinText"
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/pin"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</HorizontalScrollView>

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<body id="preview">
<h2><a id="FastHub_changelog_0"></a>FastHub changelog</h2>
<h3><a id="Version_2"></a>Version 1.4.0</h3>
<h4><a id="New_4"></a>New</h4>
<ul>
<li>Introduction new enhanced <strong><strong>FastHub</strong> Main Screen</strong> showing you what matters the most to you:
<ul>
<li>My Feeds</li>
<li>Pull Requests</li>
<li>Issues</li>
</ul>
</li>
<li><strong>Notifications</strong>, the notifications in (notification panel) is now enhanced as: <a href="https://github.com/k0shk0sh/FastHub/issues/111">#111</a>
<ul>
<li>Grouped Notifications, all under one notification.</li>
<li>Showing comments within the notification. Yaay.</li>
<li>Opening the specific view from within the notification, no more extra clicks.</li>
<li>Upon clicking a notification, it will be auto-magically marked as read unless if you disable it from the settings screen.</li>
</ul>
</li>
<li><strong>Pinned Repos</strong>, is a place that lives outside of GitHub and only exists in <strong>FastHub</strong>, you could pin any repo you like and access it faster from within the <strong>Pinned</strong> tab from MenuDrawer (works <strong>Offline</strong>). <a href="https://github.com/k0shk0sh/FastHub/issues/184">#184</a></li>
<li>Menu Drawer now has more options, and there will be more in the future:
<ul>
<li>Pinned</li>
<li>Public Gists (Previously in BottomBar)</li>
<li>Your own Gists</li>
<li>More items</li>
</ul>
</li>
<li><strong>Issues</strong> &amp; <strong>Pull Requests</strong> count, <strong>Please be aware that this rely on the Search API which mean it has API limit</strong> for more info please
<br> visit. <a href="https://developer.github.com/v3/search/#rate-limit">GitHub Developer Rate Limit</a> <a href="https://github.com/k0shk0sh/FastHub/issues/185">#185</a></li>
<li>Now Downloaded files are going to be downloaded into your <strong>sdcard/FastHub</strong> folder which results in asking a new <strong>Permission</strong>.</li>
</ul>
<h4><a id="Fixes_25"></a>Fixes</h4>
<ul>
<li>Those who uses custom build.properties in their phone to modify the display density, now the app should behave like it should and show you the
<br> right layout for your screen.<a href="https://github.com/k0shk0sh/FastHub/issues/189">#189</a></li>
<li>Files and Branches now should be downloaded in <strong>FastHub</strong> Folder. <a href="https://github.com/k0shk0sh/FastHub/issues/188">#188</a></li>
<li>Enable ads not saved upon restarting app.<a href="https://github.com/k0shk0sh/FastHub/issues/176">#176</a></li>
<li>Commit files font style. <a href="https://github.com/k0shk0sh/FastHub/issues/187">#187</a></li>
<li>And More fixed internally that I cant really remember them.</li>
</ul>
<blockquote>
<p>Please notice: if you are using Android 7 &amp; above, you might have a problem with the NightMode. its something out of FastHub league as its OS bug
<br> than <strong>FastHub</strong> due to this &amp; as per request we will end up with a <strong>Themes Engine</strong> very soon.</p>
</blockquote>
<blockquote>
<p>Please notice: Organization is my highest priority for the next release, please stay tuned &amp; patience.</p>
</blockquote>
<blockquote>
<p><strong>FastHub</strong> in a month has closed 176 issues &amp; feature requests, its a one man job, so please bare with me.</p>
</blockquote>
<p><strong>Thank you very much</strong></p>
</body>
</html>

View File

@ -1,57 +0,0 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Untitled Document.md</title><style></style></head><body id="preview">
<h2><a id="FastHub_changelog_0"></a>FastHub changelog</h2>
<h3><a id="Version_2"></a>Version 1.4.0</h3>
<h4><a id="New_4"></a>New</h4>
<ul>
<li>Introduction new enhanced <strong><strong>FastHub</strong> Main Screen</strong> showing you what matters the most to you:
<ul>
<li>My Feeds</li>
<li>Pull Requests</li>
<li>Issues</li>
</ul>
</li>
<li><strong>Notifications</strong>, the notifications in (notification panel) is now enhanced as: <a href="https://github.com/k0shk0sh/FastHub/issues/111">#111</a>
<ul>
<li>Grouped Notifications, all under one notification.</li>
<li>Showing comments within the notification. Yaay.</li>
<li>Opening the specific view from within the notification, no more extra clicks.</li>
<li>Upon clicking a notification, it will be auto-magically marked as read unless if you disable it from the settings screen.</li>
</ul>
</li>
<li><strong>Pinned Repos</strong>, is a place that lives outside of GitHub and only exists in <strong>FastHub</strong>, you could pin any repo you
like and access it faster from
within the <strong>Pinned</strong> tab from MenuDrawer (works <strong>Offline</strong>). <a href="https://github.com/k0shk0sh/FastHub/issues/184">#184</a></li>
<li>Menu Drawer now has more options, and there will be more in the future:
<ul>
<li>Pinned</li>
<li>Public Gists (Previously in BottomBar)</li>
<li>Your own Gists</li>
<li>More items</li>
</ul>
</li>
<li><strong>Issues</strong> &amp; <strong>Pull Requests</strong> count, <strong>Please be aware that this rely on the Search API which mean it has API limit</strong> for more info please<br>
visit. <a href="https://developer.github.com/v3/search/#rate-limit">GitHub Developer Rate Limit</a> <a href="https://github.com/k0shk0sh/FastHub/issues/185">#185</a></li>
<li>Now Downloaded files are going to be downloaded into your <strong>sdcard/FastHub</strong> folder which results in asking a new <strong>Permission</strong>.</li>
</ul>
<h4><a id="Fixes_25"></a>Fixes</h4>
<ul>
<li>Those who uses custom build.properties in their phone to modify the display density, now the app should behave like it should and show you the<br>
right layout for your screen.<a href="https://github.com/k0shk0sh/FastHub/issues/189">#189</a></li>
<li>Files and Branches now should be downloaded in <strong>FastHub</strong> Folder. <a href="https://github.com/k0shk0sh/FastHub/issues/188">#188</a></li>
<li>Enable ads not saved upon restarting app.<a href="https://github.com/k0shk0sh/FastHub/issues/176">#176</a></li>
<li>Commit files font style. <a href="https://github.com/k0shk0sh/FastHub/issues/187">#187</a></li>
<li>And More fixed internally that I cant really remember them.</li>
</ul>
<blockquote>
<p>Please notice: if you are using Android 7 &amp; above, you might have a problem with the NightMode. its something out of FastHub league as its OS bug<br>
than <strong>FastHub</strong> due to this &amp; as per request we will end up with a <strong>Themes Engine</strong> very soon.</p>
</blockquote>
<blockquote>
<p>Please notice: Organization is my highest priority for the next release, please stay tuned &amp; patience.</p>
</blockquote>
<blockquote>
<p><strong>FastHub</strong> in a month has closed 176 issues &amp; feature requests, its a one man job, so please bare with me.</p>
</blockquote>
<p><strong>Thank you very much</strong></p>
</body></html>

View File

@ -320,4 +320,5 @@
<string name="no_unread_notifications">No unread notifications.</string>
<string name="my_gists">My Gists</string>
<string name="changelog">Changelog</string>
<string name="notifications_hint">Click to open notifications list or swipe to dismiss</string>
</resources>