this commit fixes #384 and fixes #981

This commit is contained in:
k0shk0sh 2017-09-16 19:59:42 +02:00
parent a2750ad544
commit 4bc9bda3c5
25 changed files with 662 additions and 64 deletions

View File

@ -15,6 +15,7 @@ repository(owner: $owner, name: $name) {
columns(first: 1) {
totalCount
}
databaseId
}
}
}
@ -36,6 +37,7 @@ repository(owner: $owner, name: $name) {
columns(first: 1) {
totalCount
}
databaseId
}
}
}

View File

@ -69,10 +69,16 @@ import lombok.Setter;
String title;
Fragment fragment;
String key;
private FragmentPagerAdapterModel(String title, Fragment fragment) {
this(title, fragment, null);
}
public FragmentPagerAdapterModel(String title, Fragment fragment, String key) {
this.title = title;
this.fragment = fragment;
this.key = key;
}
@NonNull public static List<FragmentPagerAdapterModel> buildForProfile(@NonNull Context context, @NonNull String login) {
@ -245,7 +251,20 @@ import lombok.Setter;
@NonNull public static List<FragmentPagerAdapterModel> buildForProjectColumns(@NonNull List<ProjectColumnModel> models, boolean isCollaborator) {
return Stream.of(models)
.map(projectColumnModel -> new FragmentPagerAdapterModel("", ProjectColumnFragment.Companion
.newInstance(projectColumnModel, isCollaborator)))
.newInstance(projectColumnModel, isCollaborator), String.valueOf(projectColumnModel.getId())))
.toList();
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FragmentPagerAdapterModel that = (FragmentPagerAdapterModel) o;
return key != null ? key.equals(that.key) : that.key == null;
}
@Override public int hashCode() {
return key != null ? key.hashCode() : 0;
}
}

View File

@ -15,7 +15,7 @@ public class ProjectCardModel implements Parcelable {
private String url;
private String columnUrl;
private String contentUrl;
private int id;
private Integer id;
private String note;
private User creator;
private Date createdAt;
@ -85,26 +85,26 @@ public class ProjectCardModel implements Parcelable {
this.updatedAt = updatedAt;
}
public ProjectCardModel() {}
@Override public int describeContents() { return 0; }
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.url);
dest.writeString(this.columnUrl);
dest.writeString(this.contentUrl);
dest.writeInt(this.id);
dest.writeValue(this.id);
dest.writeString(this.note);
dest.writeParcelable(this.creator, flags);
dest.writeLong(this.createdAt != null ? this.createdAt.getTime() : -1);
dest.writeLong(this.updatedAt != null ? this.updatedAt.getTime() : -1);
}
public ProjectCardModel() {}
protected ProjectCardModel(Parcel in) {
this.url = in.readString();
this.columnUrl = in.readString();
this.contentUrl = in.readString();
this.id = in.readInt();
this.id = (Integer) in.readValue(Integer.class.getClassLoader());
this.note = in.readString();
this.creator = in.readParcelable(User.class.getClassLoader());
long tmpCreatedAt = in.readLong();
@ -113,7 +113,7 @@ public class ProjectCardModel implements Parcelable {
this.updatedAt = tmpUpdatedAt == -1 ? null : new Date(tmpUpdatedAt);
}
public static final Parcelable.Creator<ProjectCardModel> CREATOR = new Parcelable.Creator<ProjectCardModel>() {
public static final Creator<ProjectCardModel> CREATOR = new Creator<ProjectCardModel>() {
@Override public ProjectCardModel createFromParcel(Parcel source) {return new ProjectCardModel(source);}
@Override public ProjectCardModel[] newArray(int size) {return new ProjectCardModel[size];}

View File

@ -11,7 +11,7 @@ import java.util.Date;
public class ProjectColumnModel implements Parcelable {
private long id;
private Long id;
private String name;
private String url;
private String projectUrl;
@ -75,10 +75,12 @@ public class ProjectColumnModel implements Parcelable {
this.updatedAt = updatedAt;
}
public ProjectColumnModel() {}
@Override public int describeContents() { return 0; }
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(this.id);
dest.writeValue(this.id);
dest.writeString(this.name);
dest.writeString(this.url);
dest.writeString(this.projectUrl);
@ -87,10 +89,8 @@ public class ProjectColumnModel implements Parcelable {
dest.writeLong(this.updatedAt != null ? this.updatedAt.getTime() : -1);
}
public ProjectColumnModel() {}
protected ProjectColumnModel(Parcel in) {
this.id = in.readLong();
this.id = (Long) in.readValue(Long.class.getClassLoader());
this.name = in.readString();
this.url = in.readString();
this.projectUrl = in.readString();
@ -106,4 +106,17 @@ public class ProjectColumnModel implements Parcelable {
@Override public ProjectColumnModel[] newArray(int size) {return new ProjectColumnModel[size];}
};
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProjectColumnModel that = (ProjectColumnModel) o;
return id != null ? id.equals(that.id) : that.id == null;
}
@Override public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}

View File

@ -9,14 +9,10 @@ import com.fastaccess.helper.InputHelper;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
/**
* Created by Kosh on 17 Dec 2016, 12:17 AM
*/
@Getter @Setter
public class PullsIssuesParser implements Parcelable {
private String login;
@ -26,11 +22,23 @@ public class PullsIssuesParser implements Parcelable {
public static PullsIssuesParser getForPullRequest(@NonNull String url) {
Uri uri = Uri.parse(url);
List<String> segments = uri.getPathSegments();
if (segments == null || segments.size() < 4) return null;
if (!"pull".equals(segments.get(2))) return null;
String owner = segments.get(0);
String repo = segments.get(1);
String number = segments.get(3);
if (segments == null || segments.size() < 3) return null;
String owner = null;
String repo = null;
String number = null;
if (segments.size() > 3) {
if (("pull".equals(segments.get(2)) || "pulls".equals(segments.get(2)))) {
owner = segments.get(0);
repo = segments.get(1);
number = segments.get(3);
} else if (("pull".equals(segments.get(3)) || "pulls".equals(segments.get(3))) && segments.size() > 4) {
owner = segments.get(1);
repo = segments.get(2);
number = segments.get(4);
} else {
return null;
}
}
if (InputHelper.isEmpty(number)) return null;
int issueNumber;
try {
@ -38,6 +46,7 @@ public class PullsIssuesParser implements Parcelable {
} catch (NumberFormatException nfe) {
return null;
}
if (issueNumber < 1) return null;
PullsIssuesParser model = new PullsIssuesParser();
model.setLogin(owner);
model.setRepoId(repo);
@ -48,18 +57,32 @@ public class PullsIssuesParser implements Parcelable {
public static PullsIssuesParser getForIssue(@NonNull String url) {
Uri uri = Uri.parse(url);
List<String> segments = uri.getPathSegments();
if (segments == null || segments.size() < 4) return null;
if (!"issues".equals(segments.get(2))) return null;
String owner = segments.get(0);
String repo = segments.get(1);
String number = segments.get(3);
if (InputHelper.isEmpty(number)) return null;
if (segments == null || segments.size() < 3) return null;
String owner = null;
String repo = null;
String number = null;
if (segments.size() > 3) {
if (segments.get(2).equalsIgnoreCase("issues")) {
owner = segments.get(0);
repo = segments.get(1);
number = segments.get(3);
} else if (segments.get(3).equalsIgnoreCase("issues") && segments.size() > 4) {
owner = segments.get(1);
repo = segments.get(2);
number = segments.get(4);
} else {
return null;
}
}
if (InputHelper.isEmpty(number))
return null;
int issueNumber;
try {
issueNumber = Integer.parseInt(number);
} catch (NumberFormatException nfe) {
return null;
}
if (issueNumber < 1) return null;
PullsIssuesParser model = new PullsIssuesParser();
model.setLogin(owner);
model.setRepoId(repo);
@ -83,6 +106,30 @@ public class PullsIssuesParser implements Parcelable {
dest.writeInt(this.number);
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getRepoId() {
return repoId;
}
public void setRepoId(String repoId) {
this.repoId = repoId;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public PullsIssuesParser() {}
protected PullsIssuesParser(Parcel in) {

View File

@ -5,10 +5,8 @@ import com.fastaccess.data.dao.ProjectCardModel
import com.fastaccess.data.dao.ProjectColumnModel
import com.fastaccess.data.dao.ProjectsModel
import io.reactivex.Observable
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Path
import retrofit2.http.Query
import retrofit2.Response
import retrofit2.http.*
/**
* Created by kosh on 09/09/2017.
@ -33,4 +31,28 @@ interface ProjectsService {
@GET("projects/columns/{columnId}/cards")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun getProjectCards(@Path("columnId") columnId: Long, @Query("page") page: Int): Observable<Pageable<ProjectCardModel>>
@POST("projects/columns/{projectId}")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun createColumn(@Path("projectId") projectId: Long, @Body card: ProjectColumnModel): Observable<ProjectColumnModel>
@PATCH("projects/columns/{projectId}")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun updateColumn(@Path("projectId") projectId: Long, @Body card: ProjectColumnModel): Observable<ProjectColumnModel>
@DELETE("projects/columns/{projectId}")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun deleteColumn(@Path("projectId") projectId: Long): Observable<Response<Boolean>>
@POST("/projects/columns/{columnId}/cards")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun createCard(@Path("columnId") columnId: Long, @Body card: ProjectCardModel): Observable<ProjectCardModel>
@PATCH("projects/columns/cards/{cardId}")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun updateCard(@Path("cardId") cardId: Long, @Body card: ProjectCardModel): Observable<ProjectCardModel>
@DELETE("projects/columns/cards/{cardId}")
@Headers("Accept: application/vnd.github.inertia-preview+json")
fun deleteCard(@Path("cardId") cardId: Long): Observable<Response<Boolean>>
}

View File

@ -37,4 +37,17 @@ public class FragmentsPagerAdapter extends FragmentStatePagerAdapter {
return super.getPageWidth(position);
}
public void remove(FragmentPagerAdapterModel model) {
if (fragments != null) {
fragments.remove(model);
notifyDataSetChanged();
}
}
public void remove(int position) {
if (fragments != null) {
fragments.remove(position);
notifyDataSetChanged();
}
}
}

View File

@ -6,6 +6,8 @@ import android.widget.TextView
import butterknife.BindView
import com.fastaccess.R
import com.fastaccess.data.dao.ProjectCardModel
import com.fastaccess.data.dao.PullsIssuesParser
import com.fastaccess.helper.ParseDateFormat
import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
@ -24,9 +26,22 @@ class ColumnCardViewHolder private constructor(item: View, adapter: BaseRecycler
}
override fun bind(t: ProjectCardModel) {
title.text = t.note
addedBy.text = itemView.context.getString(R.string.card_added_by, t.creator?.login)
editCard.visibility = if (isOwner) View.VISIBLE else View.GONE
title.text = if (t.note.isNullOrBlank()) {
val issue = PullsIssuesParser.getForIssue(t.contentUrl)
if (issue != null) {
"${issue.login}/${issue.repoId}/${issue.number}"
} else {
val pr = PullsIssuesParser.getForPullRequest(t.contentUrl)
if (pr != null) {
"${pr.login}/${pr.repoId}/${pr.number}"
} else {
"(FastHub) - to be fixed by GitHub! Sorry!"
}
}
} else {
t.note
}
addedBy.text = itemView.context.getString(R.string.card_added_by, t.creator?.login, ParseDateFormat.getTimeAgo(t.createdAt))
}
companion object {

View File

@ -20,6 +20,7 @@ import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView;
import butterknife.BindString;
import butterknife.BindView;
import es.dmoral.toasty.Toasty;
/**
* Created by Kosh on 15 Feb 2017, 10:29 PM
@ -104,8 +105,13 @@ public class PullRequestFilesViewHolder extends BaseViewHolder<CommitFileChanges
if (adapter != null) {
CommitFileChanges model = (CommitFileChanges) adapter.getItem(position);
if (model.getLinesModel() != null && !model.getLinesModel().isEmpty()) {
patch.setAdapter(new CommitLinesAdapter(model.getLinesModel(), this));
patch.setVisibility(View.VISIBLE);
if (model.getLinesModel().size() <= 100) {
patch.setAdapter(new CommitLinesAdapter(model.getLinesModel(), this));
patch.setVisibility(View.VISIBLE);
} else {
Toasty.warning(itemView.getContext(),itemView.getResources().getString(R.string.too_large_changes)).show();
return;
}
} else {
patch.swapAdapter(null, true);
patch.setVisibility(View.GONE);

View File

@ -31,6 +31,7 @@ import com.fastaccess.data.dao.model.Login;
import com.fastaccess.helper.AppHelper;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.Logger;
import com.fastaccess.helper.PrefGetter;
import com.fastaccess.helper.RxHelper;
import com.fastaccess.helper.ViewHelper;
@ -157,8 +158,6 @@ public abstract class BaseActivity<V extends BaseMvp.FAView, P extends BasePrese
boolean logout = bundle.getBoolean("logout");
if (logout) {
onRequireLogin();
// if(App.getInstance().getGoogleApiClient().isConnected())
// Auth.CredentialsApi.disableAutoSignIn(App.getInstance().getGoogleApiClient());
}
}
}//pass
@ -196,6 +195,7 @@ public abstract class BaseActivity<V extends BaseMvp.FAView, P extends BasePrese
@Override public void hideProgress() {
ProgressDialogFragment fragment = (ProgressDialogFragment) AppHelper.getFragmentByTag(getSupportFragmentManager(),
ProgressDialogFragment.TAG);
Logger.e(fragment);
if (fragment != null) {
isProgressShowing = false;
fragment.dismiss();

View File

@ -40,9 +40,9 @@ class AddGistBottomSheetDialog : BaseDialogFragment<AddGistMvp.View, AddGistPres
override fun onAttach(context: Context) {
super.onAttach(context)
when {
parentFragment is AddGistFileListener -> addFileListener = parentFragment as AddGistFileListener
context is AddGistFileListener -> addFileListener = context
addFileListener = when {
parentFragment is AddGistFileListener -> parentFragment as AddGistFileListener
context is AddGistFileListener -> context
else -> throw NullPointerException("${context::class.java.simpleName} most implement AddGistFileListener")
}
}
@ -53,7 +53,7 @@ class AddGistBottomSheetDialog : BaseDialogFragment<AddGistMvp.View, AddGistPres
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
return super.onCreateView(inflater, container, savedInstanceState)
}

View File

@ -1,5 +1,6 @@
package com.fastaccess.ui.modules.repos.projects.columns
import android.content.Context
import android.os.Bundle
import android.support.annotation.StringRes
import android.support.v4.widget.SwipeRefreshLayout
@ -11,11 +12,15 @@ import com.fastaccess.data.dao.ProjectCardModel
import com.fastaccess.data.dao.ProjectColumnModel
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.ColumnCardAdapter
import com.fastaccess.ui.base.BaseFragment
import com.fastaccess.ui.modules.repos.projects.crud.ProjectCurdDialogFragment
import com.fastaccess.ui.modules.repos.projects.details.ProjectPagerMvp
import com.fastaccess.ui.widgets.FontTextView
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
@ -33,11 +38,38 @@ class ProjectColumnFragment : BaseFragment<ProjectColumnMvp.View, ProjectColumnP
private var onLoadMore: OnLoadMore<Long>? = null
private val adapter by lazy { ColumnCardAdapter(presenter.getCards(), isOwner()) }
private var pageCallback: ProjectPagerMvp.DeletePageListener? = null
@OnClick(R.id.editColumn) fun onEditColumn() {}
@OnClick(R.id.deleteColumn) fun onDeleteColumn() {}
@OnClick(R.id.addCard) fun onAddCard() {}
override fun onAttach(context: Context?) {
super.onAttach(context)
pageCallback = when {
parentFragment is ProjectPagerMvp.DeletePageListener -> parentFragment as ProjectPagerMvp.DeletePageListener
context is ProjectPagerMvp.DeletePageListener -> context
else -> null
}
}
override fun onDetach() {
pageCallback = null
super.onDetach()
}
@OnClick(R.id.editColumn) fun onEditColumn() {
ProjectCurdDialogFragment.newInstance(getColumn().name)
.show(childFragmentManager, ProjectCurdDialogFragment.TAG)
}
@OnClick(R.id.deleteColumn) fun onDeleteColumn() {
MessageDialogView.newInstance(getString(R.string.delete), getString(R.string.confirm_message),
false, MessageDialogView.getYesNoBundle(context))
.show(childFragmentManager, MessageDialogView.TAG)
}
@OnClick(R.id.addCard) fun onAddCard() {
ProjectCurdDialogFragment.newInstance(isCard = true)
.show(childFragmentManager, ProjectCurdDialogFragment.TAG)
}
override fun onNotifyAdapter(items: List<ProjectCardModel>?, page: Int) {
hideProgress()
@ -111,6 +143,78 @@ class ProjectColumnFragment : BaseFragment<ProjectColumnMvp.View, ProjectColumnP
super.onDestroyView()
}
override fun onCreatedOrEdited(text: String, isCard: Boolean, position: Int) {
Logger.e(text, isCard, position)
if (!isCard) {
columnName.text = text
presenter.onEditOrDeleteColumn(text, getColumn())
} else {
if (position == -1) {
presenter.createCard(text, getColumn().id)
} else {
presenter.editCard(text, adapter.getItem(position), position)
}
}
}
override fun onMessageDialogActionClicked(isOk: Boolean, bundle: Bundle?) {
super.onMessageDialogActionClicked(isOk, bundle)
if (isOk) {
if (bundle != null) {
if (bundle.containsKey(BundleConstant.ID)) {
val position = bundle.getInt(BundleConstant.ID)
presenter.onDeleteCard(position, adapter.getItem(position))
} else {
presenter.onEditOrDeleteColumn(null, getColumn())
}
} else {
presenter.onEditOrDeleteColumn(null, getColumn())
}
}
}
override fun deleteColumn() {
pageCallback?.onDeletePage(getColumn())
hideBlockingProgress()
}
override fun showBlockingProgress() {
super.showProgress(0)
}
override fun hideBlockingProgress() {
super.hideProgress()
}
override fun isOwner(): Boolean = arguments.getBoolean(BundleConstant.EXTRA)
override fun onDeleteCard(position: Int) {
val yesNoBundle = MessageDialogView.getYesNoBundle(context)
yesNoBundle.putInt(BundleConstant.ID, position)
MessageDialogView.newInstance(getString(R.string.delete), getString(R.string.confirm_message),
false, yesNoBundle).show(childFragmentManager, MessageDialogView.TAG)
}
override fun onEditCard(note: String?, position: Int) {
ProjectCurdDialogFragment.newInstance(note, true, position)
.show(childFragmentManager, ProjectCurdDialogFragment.TAG)
}
override fun addCard(it: ProjectCardModel) {
hideBlockingProgress()
adapter.addItem(it, 0)
}
override fun updateCard(response: ProjectCardModel, position: Int) {
hideBlockingProgress()
adapter.swapItem(response, position)
}
override fun onRemoveCard(position: Int) {
hideBlockingProgress()
adapter.removeItem(position)
}
private fun showReload() {
hideProgress()
stateLayout.showReload(adapter.itemCount)
@ -118,8 +222,6 @@ class ProjectColumnFragment : BaseFragment<ProjectColumnMvp.View, ProjectColumnP
private fun getColumn(): ProjectColumnModel = arguments.getParcelable(BundleConstant.ITEM)
private fun isOwner(): Boolean = arguments.getBoolean(BundleConstant.EXTRA)
companion object {
fun newInstance(column: ProjectColumnModel, isCollaborator: Boolean): ProjectColumnFragment {
val fragment = ProjectColumnFragment()

View File

@ -1,8 +1,10 @@
package com.fastaccess.ui.modules.repos.projects.columns
import com.fastaccess.data.dao.ProjectCardModel
import com.fastaccess.data.dao.ProjectColumnModel
import com.fastaccess.provider.rest.loadmore.OnLoadMore
import com.fastaccess.ui.base.mvp.BaseMvp
import com.fastaccess.ui.modules.repos.projects.crud.ProjectCurdDialogFragment
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
/**
@ -10,12 +12,25 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
*/
interface ProjectColumnMvp {
interface View : BaseMvp.FAView {
interface View : BaseMvp.FAView, ProjectCurdDialogFragment.OnProjectEditedCallback {
fun onNotifyAdapter(items: List<ProjectCardModel>?, page: Int)
fun getLoadMore(): OnLoadMore<Long>
fun deleteColumn()
fun showBlockingProgress()
fun hideBlockingProgress()
fun isOwner(): Boolean
fun onDeleteCard(position: Int)
fun onEditCard(note: String?, position: Int)
fun addCard(it: ProjectCardModel)
fun updateCard(response: ProjectCardModel, position: Int)
fun onRemoveCard(position: Int)
}
interface Presenter : BaseViewHolder.OnItemClickListener<ProjectCardModel>, BaseMvp.PaginationListener<Long> {
fun getCards(): ArrayList<ProjectCardModel>
fun onEditOrDeleteColumn(text: String? = null, column: ProjectColumnModel)
fun onDeleteCard(position: Int, card: ProjectCardModel)
fun createCard(text: String, columnId: Long)
fun editCard(text: String, card: ProjectCardModel, position: Int)
}
}

View File

@ -1,9 +1,16 @@
package com.fastaccess.ui.modules.repos.projects.columns
import android.view.View
import android.widget.PopupMenu
import com.fastaccess.R
import com.fastaccess.data.dao.ProjectCardModel
import com.fastaccess.data.dao.ProjectColumnModel
import com.fastaccess.helper.ActivityHelper
import com.fastaccess.helper.AppHelper
import com.fastaccess.helper.Logger
import com.fastaccess.helper.RxHelper
import com.fastaccess.provider.rest.RestProvider
import com.fastaccess.provider.scheme.SchemeParser
import com.fastaccess.ui.base.mvp.presenter.BasePresenter
import java.util.*
@ -13,13 +20,41 @@ import java.util.*
class ProjectColumnPresenter : BasePresenter<ProjectColumnMvp.View>(), ProjectColumnMvp.Presenter {
private val projects = ArrayList<ProjectCardModel>()
private var page: Int = 0
private var previousTotal: Int = 0
private var lastPage = Integer.MAX_VALUE
override fun onItemClick(position: Int, v: View?, item: ProjectCardModel?) {}
override fun onItemClick(position: Int, v: View, item: ProjectCardModel) {
if (v.id == R.id.editCard) {
view?.let {
val popupMenu = PopupMenu(v.context, v)
popupMenu.inflate(R.menu.project_card_menu)
popupMenu.menu.findItem(R.id.share).isVisible = !item.contentUrl.isNullOrBlank()
popupMenu.menu.findItem(R.id.copy).isVisible = !item.contentUrl.isNullOrBlank()
popupMenu.menu.findItem(R.id.edit).isVisible = it.isOwner() && item.note.isNullOrBlank()
popupMenu.menu.findItem(R.id.delete).isVisible = it.isOwner() && item.note.isNullOrBlank()
popupMenu.setOnMenuItemClickListener {
when (it.itemId) {
R.id.edit -> sendToView { it.onEditCard(item.note, position) }
R.id.delete -> sendToView { it.onDeleteCard(position) }
R.id.share -> if (!item.contentUrl.isNullOrBlank()) {
ActivityHelper.shareUrl(v.context, item.contentUrl)
}
R.id.copy -> if (!item.contentUrl.isNullOrBlank()) {
AppHelper.copyToClipboard(v.context, item.contentUrl)
}
}
return@setOnMenuItemClickListener true
}
popupMenu.show()
}
} else {
if (!item.contentUrl.isNullOrBlank()) {
SchemeParser.launchUri(v.context, item.contentUrl)
}
}
}
override fun onItemLongClick(position: Int, v: View?, item: ProjectCardModel?) {}
@ -56,4 +91,90 @@ class ProjectColumnPresenter : BasePresenter<ProjectColumnMvp.View>(), ProjectCo
return true
}
override fun onEditOrDeleteColumn(text: String?, column: ProjectColumnModel) {
if (text.isNullOrBlank()) {
manageDisposable(RxHelper.getObservable(RestProvider.getProjectsService(isEnterprise).deleteColumn(column.id))
.doOnSubscribe {
showBlockingProgress()
}
.subscribe({
if (it.code() == 204) {
sendToView { it.deleteColumn() }
} else {
sendToView { it.showMessage(R.string.error, R.string.network_error) }
}
}, {
hideBlockingProgress()
onError(it)
}))
} else {
val body = ProjectColumnModel()
body.name = text
manageDisposable(RxHelper.getObservable(RestProvider.getProjectsService(isEnterprise).updateColumn(column.id, body))
.doOnSubscribe {
showBlockingProgress()
}
.subscribe({
hideBlockingProgress()
}, {
hideBlockingProgress()
onError(it)
}))
}
}
override fun onDeleteCard(position: Int, card: ProjectCardModel) {
manageDisposable(RxHelper.getObservable(RestProvider.getProjectsService(isEnterprise).deleteCard(card.id.toLong()))
.doOnSubscribe {
showBlockingProgress()
}
.subscribe({
if (it.code() == 204) {
sendToView { it.onRemoveCard(position) }
} else {
sendToView { it.showMessage(R.string.error, R.string.network_error) }
}
}, {
hideBlockingProgress()
onError(it)
}))
}
override fun createCard(text: String, columnId: Long) {
val body = ProjectCardModel()
body.note = text
manageDisposable(RxHelper.getObservable(RestProvider.getProjectsService(isEnterprise).createCard(columnId, body))
.doOnSubscribe {
showBlockingProgress()
}
.subscribe({ response ->
sendToView { it.addCard(response) }
}, {
hideBlockingProgress()
onError(it)
}))
}
override fun editCard(text: String, card: ProjectCardModel, position: Int) {
val body = ProjectCardModel()
body.note = text
manageDisposable(RxHelper.getObservable(RestProvider.getProjectsService(isEnterprise).updateCard(card.id.toLong(), body))
.doOnSubscribe {
showBlockingProgress()
}
.subscribe({ response ->
sendToView { it.updateCard(response, position) }
}, {
hideBlockingProgress()
onError(it)
}))
}
private fun showBlockingProgress() {
sendToView({ v -> v.showBlockingProgress() })
}
private fun hideBlockingProgress() {
sendToView({ v -> v.hideBlockingProgress() })
}
}

View File

@ -0,0 +1,120 @@
package com.fastaccess.ui.modules.repos.projects.crud
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
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.widget.EditText
import butterknife.BindView
import com.fastaccess.R
import com.fastaccess.helper.BundleConstant
import com.fastaccess.helper.Bundler
import com.fastaccess.helper.InputHelper
import com.fastaccess.provider.emoji.Emoji
import com.fastaccess.ui.base.BaseDialogFragment
import com.fastaccess.ui.base.mvp.BaseMvp
import com.fastaccess.ui.base.mvp.presenter.BasePresenter
import com.fastaccess.ui.modules.editor.emoji.EmojiMvp
import com.fastaccess.ui.modules.editor.popup.EditorLinkImageMvp
import com.fastaccess.ui.widgets.markdown.MarkDownLayout
import com.fastaccess.ui.widgets.markdown.MarkdownEditText
/**
* Created by Hashemsergani on 15.09.17.
*/
class ProjectCurdDialogFragment : BaseDialogFragment<BaseMvp.FAView, BasePresenter<BaseMvp.FAView>>(),
EditorLinkImageMvp.EditorLinkCallback, MarkDownLayout.MarkdownListener, EmojiMvp.EmojiCallback {
@BindView(R.id.editText) lateinit var editText: MarkdownEditText
@BindView(R.id.toolbar) lateinit var toolbar: Toolbar
@BindView(R.id.markDownLayout) lateinit var markDownLayout: MarkDownLayout
private var onProjectEditedCallback: OnProjectEditedCallback? = null
override fun onAttach(context: Context) {
super.onAttach(context)
onProjectEditedCallback = when {
parentFragment is OnProjectEditedCallback -> parentFragment as OnProjectEditedCallback
context is OnProjectEditedCallback -> context
else -> throw NullPointerException("${context::class.java.simpleName} most implement OnProjectEditedCallback")
}
}
override fun onDetach() {
onProjectEditedCallback = null
super.onDetach()
}
override fun fragmentLayout(): Int = R.layout.edit_project_column_note_layout
override fun providePresenter(): BasePresenter<BaseMvp.FAView> = BasePresenter()
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 onFragmentCreated(view: View, savedInstanceState: Bundle?) {
markDownLayout.markdownListener = this
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() }
val position: Int = arguments.getInt(BundleConstant.ID, -1)
val isCard: Boolean = arguments.getBoolean(BundleConstant.EXTRA)
if (savedInstanceState == null) {
editText.setText(arguments.getString(BundleConstant.ITEM))
}
toolbar.setOnMenuItemClickListener {
if (it.itemId == R.id.submit) {
val isEmpty = editText.text.isNullOrBlank()
editText.error = if (isEmpty) getString(R.string.required_field) else null
if (!isEmpty) {
onProjectEditedCallback?.onCreatedOrEdited(InputHelper.toString(editText), isCard, position)
dismiss()
}
}
return@setOnMenuItemClickListener true
}
}
override fun getEditText(): EditText = editText
override fun fragmentManager(): FragmentManager = childFragmentManager
override fun getSavedText(): CharSequence? = editText.savedText
override fun onAppendLink(title: String?, link: String?, isLink: Boolean) {
markDownLayout.onAppendLink(title, link, isLink)
}
@SuppressLint("SetTextI18n")
override fun onEmojiAdded(emoji: Emoji?) {
markDownLayout.onEmojiAdded(emoji)
}
companion object {
val TAG = ProjectCurdDialogFragment::class.java.simpleName!!
fun newInstance(text: String? = null, isCard: Boolean = false, position: Int = -1): ProjectCurdDialogFragment {
val fragment = ProjectCurdDialogFragment()
fragment.arguments = Bundler.start()
.put(BundleConstant.ITEM, text)
.put(BundleConstant.EXTRA, isCard)
.put(BundleConstant.ID, position)
.end()
return fragment
}
}
interface OnProjectEditedCallback {
fun onCreatedOrEdited(text: String, isCard: Boolean, position: Int)
}
}

View File

@ -8,6 +8,7 @@ import android.view.MenuItem
import android.view.View
import butterknife.BindView
import com.airbnb.lottie.LottieAnimationView
import com.evernote.android.state.State
import com.fastaccess.R
import com.fastaccess.data.dao.FragmentPagerAdapterModel
import com.fastaccess.data.dao.NameParser
@ -25,9 +26,9 @@ import com.fastaccess.ui.widgets.CardsPagerTransformerBasic
class ProjectPagerActivity : BaseActivity<ProjectPagerMvp.View, ProjectPagerPresenter>(), ProjectPagerMvp.View {
@BindView(R.id.pager) lateinit var pager: ViewPager
@BindView(R.id.loading) lateinit var loading: LottieAnimationView
@State var isProgressShowing = false
override fun canBack(): Boolean = true
@ -38,7 +39,7 @@ class ProjectPagerActivity : BaseActivity<ProjectPagerMvp.View, ProjectPagerPres
override fun onInitPager(list: List<ProjectColumnModel>) {
hideProgress()
pager.adapter = FragmentsPagerAdapter(supportFragmentManager, FragmentPagerAdapterModel
.buildForProjectColumns(list, presenter.isCollaborator))
.buildForProjectColumns(list, presenter.viewerCanUpdate))
}
override fun showMessage(titleRes: Int, msgRes: Int) {
@ -57,11 +58,13 @@ class ProjectPagerActivity : BaseActivity<ProjectPagerMvp.View, ProjectPagerPres
}
override fun showProgress(resId: Int) {
isProgressShowing = true
loading.visibility = View.VISIBLE
loading.playAnimation()
}
override fun hideProgress() {
isProgressShowing = false
loading.cancelAnimation()
loading.visibility = View.GONE
}
@ -87,9 +90,13 @@ class ProjectPagerActivity : BaseActivity<ProjectPagerMvp.View, ProjectPagerPres
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (isProgressShowing) {
showProgress(0)
} else {
hideProgress()
}
pager.clipToPadding = false
val pageMargin = resources.getDimensionPixelSize(R.dimen.spacing_normal)
pager.pageMargin = pageMargin
@ -105,6 +112,11 @@ class ProjectPagerActivity : BaseActivity<ProjectPagerMvp.View, ProjectPagerPres
}
}
override fun onDeletePage(model: ProjectColumnModel) {
presenter.getColumns().remove(model)
onInitPager(presenter.getColumns())
}
companion object {
fun startActivity(context: Context, login: String, repoId: String, projectId: Long) {
context.startActivity(getIntent(context, login, repoId, projectId))
@ -122,5 +134,4 @@ class ProjectPagerActivity : BaseActivity<ProjectPagerMvp.View, ProjectPagerPres
}
}

View File

@ -9,7 +9,7 @@ import com.fastaccess.ui.base.mvp.BaseMvp
*/
interface ProjectPagerMvp {
interface View : BaseMvp.FAView {
interface View : BaseMvp.FAView, DeletePageListener {
fun onInitPager(list: List<ProjectColumnModel>)
}
@ -20,4 +20,8 @@ interface ProjectPagerMvp {
fun getColumns(): ArrayList<ProjectColumnModel>
}
interface DeletePageListener {
fun onDeletePage(model: ProjectColumnModel)
}
}

View File

@ -21,7 +21,7 @@ class ProjectPagerPresenter : BasePresenter<ProjectPagerMvp.View>(), ProjectPage
@com.evernote.android.state.State var projectId: Long = -1
@com.evernote.android.state.State var repoId: String = ""
@com.evernote.android.state.State var login: String = ""
@com.evernote.android.state.State var isCollaborator: Boolean = false
@com.evernote.android.state.State var viewerCanUpdate: Boolean = false
override fun getColumns(): ArrayList<ProjectColumnModel> = columns
@ -30,7 +30,7 @@ class ProjectPagerPresenter : BasePresenter<ProjectPagerMvp.View>(), ProjectPage
makeRestCall(Observable.zip(RestProvider.getProjectsService(isEnterprise).getProjectColumns(projectId),
RestProvider.getRepoService(isEnterprise).isCollaborator(login, repoId, Login.getUser().login),
BiFunction { items: Pageable<ProjectColumnModel>, response: Response<Boolean> ->
isCollaborator = response.code() == 204
viewerCanUpdate = response.code() == 204
return@BiFunction items
})
.flatMap {

View File

@ -27,7 +27,9 @@ class RepoProjectPresenter : BasePresenter<RepoProjectMvp.View>(), RepoProjectMv
val pages = arrayListOf<String>()
override fun onItemClick(position: Int, v: View, item: RepoProjectsOpenQuery.Node) {
ProjectPagerActivity.startActivity(v.context, login, repoId, item.number().toLong())
item.databaseId()?.let {
ProjectPagerActivity.startActivity(v.context, login, repoId, it.toLong())
}
}
override fun onItemLongClick(position: Int, v: View?, item: RepoProjectsOpenQuery.Node?) {}
@ -114,7 +116,7 @@ class RepoProjectPresenter : BasePresenter<RepoProjectMvp.View>(), RepoProjectMv
it.onEach {
val columns = RepoProjectsOpenQuery.Columns(it.columns().__typename(), it.columns().totalCount())
val node = RepoProjectsOpenQuery.Node(it.__typename(), it.name(), it.number(), it.body(),
it.createdAt(), it.id(), it.viewerCanUpdate(), columns)
it.createdAt(), it.id(), it.viewerCanUpdate(), columns, it.databaseId())
toConvert.add(node)
}
list.addAll(toConvert)

View File

@ -164,4 +164,11 @@ public class MessageDialogView extends BaseBottomSheetDialog {
.put("hideCancel", hideCancel)
.end();
}
@NonNull public static Bundle getYesNoBundle(@NonNull Context context) {
return Bundler.start()
.put("primary_extra", context.getString(R.string.yes))
.put("secondary_extra", context.getString(R.string.no))
.end();
}
}

View File

@ -131,7 +131,11 @@ public abstract class BaseRecyclerAdapter<M, VH extends BaseViewHolder,
public void addItem(M item) {
removeProgress();
data.add(item);
notifyItemInserted(data.size() - 1);
if (data.size() == 0) {
notifyDataSetChanged();
} else {
notifyItemInserted(data.size() - 1);
}
}
@SuppressWarnings("WeakerAccess") public void addItems(@NonNull List<M> items) {

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?card_background"
android:orientation="vertical">
<include layout="@layout/appbar_elevation_dark"/>
<LinearLayout
android:id="@+id/parentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.fastaccess.ui.widgets.markdown.MarkDownLayout
android:id="@+id/markDownLayout"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:orientation="horizontal"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_xs_large"
android:layout_marginTop="@dimen/spacing_normal"
android:paddingEnd="@dimen/spacing_xs_large"
android:paddingStart="@dimen/spacing_xs_large"
app:hintTextAppearance="@style/TextAppearance.AppCompat.Title">
<com.fastaccess.ui.widgets.markdown.MarkdownEditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/content"
android:inputType="textMultiLine"
android:maxLines="10"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</LinearLayout>

View File

@ -39,9 +39,7 @@
android:layout_gravity="top"
android:background="?selectableItemBackgroundBorderless"
android:padding="@dimen/spacing_micro"
android:src="@drawable/ic_overflow"
android:tint="@color/white"
android:visibility="gone"/>
android:src="@drawable/ic_overflow"/>
</LinearLayout>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/edit"
android:icon="@drawable/ic_edit"
android:title="@string/edit"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/delete"
android:icon="@drawable/ic_trash"
android:title="@string/delete"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/share"
android:icon="@drawable/ic_share"
android:title="@string/share"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/copy"
android:icon="@drawable/ic_copy"
android:title="@string/copy"
app:showAsAction="ifRoom"/>
</menu>

View File

@ -564,5 +564,6 @@
<string name="projects">Projects</string>
<string name="no_projects">No Projects</string>
<string name="no_cards">No Cards</string>
<string name="card_added_by">Added by %s</string>
<string name="card_added_by">Added by %s %s</string>
<string name="too_large_changes">Changes are large, please open in browser</string>
</resources>