diff --git a/README.md b/README.md index cd664b35..17c374c0 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://gitea.com/api/v1/repos/gitnex/GitNex/releases&query=$[0].tag_name)](https://gitea.com/gitnex/GitNex/releases) [![Build Status](https://drone.gitea.com/api/badges/gitnex/GitNex/status.svg)](https://drone.gitea.com/gitnex/GitNex) [![Crowdin](https://badges.crowdin.net/gitnex/localized.svg)](https://crowdin.com/project/gitnex) +[![Join the Discord chat at https://discord.gg/FbSS4rf](https://img.shields.io/discord/632219664587685908.svg)](https://discord.gg/FbSS4rf) [Become a Patroen](https://www.patreon.com/mmarif) [Donate using Liberapay](https://liberapay.com/mmarif/donate) @@ -90,5 +91,6 @@ Open source libraries - Caverock/androidsvg - Droidsonroids.gif/android-gif-drawable - Barteksc/AndroidPdfViewer +- Mikepenz/fastadapter [Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif) diff --git a/app/build.gradle b/app/build.gradle index d6ea30b5..e2460f4a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,14 +33,15 @@ configurations { dependencies { def lifecycle_version = "2.2.0" - final def markwon_version = '4.2.1' + def markwon_version = "4.2.1" + def fastadapter = "3.3.1" implementation fileTree(include: ['*.jar'], dir: 'libs') implementation "androidx.appcompat:appcompat:1.1.0" implementation "com.google.android.material:material:1.2.0-alpha05" implementation "androidx.constraintlayout:constraintlayout:1.1.3" implementation "androidx.legacy:legacy-support-v4:1.0.0" - testImplementation 'junit:junit:4.13' + testImplementation "junit:junit:4.13" androidTestImplementation "androidx.test:runner:1.2.0" androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0" implementation "com.github.vihtarb:tooltip:0.2.0" @@ -79,4 +80,8 @@ dependencies { implementation "com.github.chrisbanes:PhotoView:2.3.0" implementation "com.pddstudio:highlightjs-android:1.5.0" implementation "com.github.barteksc:android-pdf-viewer:3.2.0-beta.1" + //noinspection GradleDependency + implementation "com.mikepenz:fastadapter:$fastadapter" + implementation "com.mikepenz:fastadapter-commons:$fastadapter" + implementation "com.mikepenz:fastadapter-extensions:$fastadapter" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a3415c93..d029de5d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -73,6 +73,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/org/mian/gitnex/activities/CommitsActivity.java b/app/src/main/java/org/mian/gitnex/activities/CommitsActivity.java new file mode 100644 index 00000000..60df3de6 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/activities/CommitsActivity.java @@ -0,0 +1,325 @@ +package org.mian.gitnex.activities; + +import android.os.Bundle; +import android.os.Handler; +import android.text.method.ScrollingMovementMethod; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import com.mikepenz.fastadapter.IItemAdapter; +import com.mikepenz.fastadapter.adapters.ItemAdapter; +import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter; +import com.mikepenz.fastadapter.listeners.ItemFilterListener; +import com.mikepenz.fastadapter_extensions.items.ProgressItem; +import com.mikepenz.fastadapter_extensions.scroll.EndlessRecyclerOnScrollListener; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.items.CommitsItems; +import org.mian.gitnex.models.Commits; +import org.mian.gitnex.util.TinyDB; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import static com.mikepenz.fastadapter.adapters.ItemAdapter.items; + +/** + * Author M M Arif + */ + +public class CommitsActivity extends BaseActivity implements ItemFilterListener { + + private View.OnClickListener onClickListener; + private TextView noData; + private ProgressBar progressBar; + private SwipeRefreshLayout swipeRefreshLayout; + private String TAG = "CommitsActivity - "; + private int resultLimit = 50; + private boolean loadNextFlag = false; + + private List items = new ArrayList<>(); + private FastItemAdapter fastItemAdapter; + private ItemAdapter footerAdapter; + private EndlessRecyclerOnScrollListener endlessRecyclerOnScrollListener; + + @Override + protected int getLayoutResourceId(){ + return R.layout.activity_commits; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + TinyDB tinyDb = new TinyDB(getApplicationContext()); + final String instanceUrl = tinyDb.getString("instanceUrl"); + final String loginUid = tinyDb.getString("loginUid"); + final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); + String repoFullName = tinyDb.getString("repoFullName"); + String[] parts = repoFullName.split("/"); + final String repoOwner = parts[0]; + final String repoName = parts[1]; + + String branchName = getIntent().getStringExtra("branchName"); + + TextView toolbar_title = findViewById(R.id.toolbar_title); + toolbar_title.setMovementMethod(new ScrollingMovementMethod()); + toolbar_title.setText(branchName); + + ImageView closeActivity = findViewById(R.id.close); + noData = findViewById(R.id.noDataCommits); + progressBar = findViewById(R.id.progress_bar); + swipeRefreshLayout = findViewById(R.id.pullToRefresh); + + RecyclerView recyclerView = findViewById(R.id.recyclerView); + recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); + recyclerView.setHasFixedSize(true); + + initCloseListener(); + closeActivity.setOnClickListener(onClickListener); + + fastItemAdapter = new FastItemAdapter<>(); + fastItemAdapter.withSelectable(true); + + footerAdapter = items(); + //noinspection unchecked + fastItemAdapter.addAdapter(1, footerAdapter); + + fastItemAdapter.getItemFilter().withFilterPredicate((IItemAdapter.Predicate) (item, constraint) -> item.getCommitTitle().toLowerCase().contains(Objects.requireNonNull(constraint).toString().toLowerCase())); + + fastItemAdapter.getItemFilter().withItemFilterListener(this); + + recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); + recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.setAdapter(fastItemAdapter); + + endlessRecyclerOnScrollListener = new EndlessRecyclerOnScrollListener(footerAdapter) { + + @Override + public void onLoadMore(final int currentPage) { + + loadNext(instanceUrl, instanceToken, repoOwner, repoName, currentPage, branchName); + + } + + }; + + swipeRefreshLayout.setOnRefreshListener(() -> { + + progressBar.setVisibility(View.VISIBLE); + fastItemAdapter.clear(); + endlessRecyclerOnScrollListener.resetPageCount(); + swipeRefreshLayout.setRefreshing(false); + + }); + + recyclerView.addOnScrollListener(endlessRecyclerOnScrollListener); + + loadInitial(instanceUrl, instanceToken, repoOwner, repoName, branchName); + + assert savedInstanceState != null; + fastItemAdapter.withSavedInstanceState(savedInstanceState); + + } + + private void loadInitial(String instanceUrl, String token, String repoOwner, String repoName, String branchName) { + + Call> call = RetrofitClient + .getInstance(instanceUrl, getApplicationContext()) + .getApiInterface() + .getRepositoryCommits(token, repoOwner, repoName, 1, branchName); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if (response.isSuccessful()) { + + assert response.body() != null; + + if(response.body().size() > 0) { + + if(response.body().size() == resultLimit) { + loadNextFlag = true; + } + + for (int i = 0; i < response.body().size(); i++) { + + items.add(new CommitsItems(getApplicationContext()).withNewItems(response.body().get(i).getCommit().getMessage(), response.body().get(i).getHtml_url(), + response.body().get(i).getCommit().getCommitter().getName(), response.body().get(i).getCommit().getCommitter().getDate())); + + } + + fastItemAdapter.add(items); + + } + else { + + noData.setVisibility(View.VISIBLE); + + } + + progressBar.setVisibility(View.GONE); + + } + else { + + Log.e(TAG, String.valueOf(response.code())); + + } + + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + + Log.e(TAG, t.toString()); + + } + + }); + + } + + private void loadNext(String instanceUrl, String token, String repoOwner, String repoName, final int currentPage, String branchName) { + + footerAdapter.clear(); + //noinspection unchecked + footerAdapter.add(new ProgressItem().withEnabled(false)); + Handler handler = new Handler(); + + handler.postDelayed(() -> { + + Call> call = RetrofitClient + .getInstance(instanceUrl, getApplicationContext()) + .getApiInterface() + .getRepositoryCommits(token, repoOwner, repoName, currentPage + 1, branchName); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if (response.isSuccessful()) { + + assert response.body() != null; + + if (response.body().size() > 0) { + + loadNextFlag = response.body().size() == resultLimit; + + for (int i = 0; i < response.body().size(); i++) { + + fastItemAdapter.add(fastItemAdapter.getAdapterItemCount(), new CommitsItems(getApplicationContext()).withNewItems(response.body().get(i).getCommit().getMessage(), + response.body().get(i).getHtml_url(), response.body().get(i).getCommit().getCommitter().getName(), + response.body().get(i).getCommit().getCommitter().getDate())); + + } + + footerAdapter.clear(); + + } + else { + + footerAdapter.clear(); + } + + progressBar.setVisibility(View.GONE); + + } + else { + + Log.e(TAG, String.valueOf(response.code())); + + } + + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + + Log.e(TAG, t.toString()); + + } + + }); + + }, 1000); + + if(!loadNextFlag) { + + footerAdapter.clear(); + + } + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.search_menu, menu); + + MenuItem searchItem = menu.findItem(R.id.action_search); + androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); + searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + fastItemAdapter.filter(newText); + return true; + } + + }); + + endlessRecyclerOnScrollListener.enable(); + return super.onCreateOptionsMenu(menu); + + } + + @Override + public void itemsFiltered(@Nullable CharSequence constraint, @Nullable List results) { + endlessRecyclerOnScrollListener.disable(); + } + + @Override + public void onReset() { + endlessRecyclerOnScrollListener.enable(); + } + + private void initCloseListener() { + onClickListener = view -> { + getIntent().removeExtra("branchName"); + finish(); + }; + } + +} + + diff --git a/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java b/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java index 17ff3cef..dd0d177a 100644 --- a/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java @@ -23,6 +23,7 @@ import androidx.appcompat.app.AlertDialog; import com.tooltip.Tooltip; import org.mian.gitnex.R; import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.helpers.NetworkObserver; import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.VersionCheck; import org.mian.gitnex.models.GiteaVersion; @@ -65,7 +66,7 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener super.onCreate(savedInstanceState); TinyDB tinyDb = new TinyDB(getApplicationContext()); - boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); + NetworkObserver networkMonitor = new NetworkObserver(this); loginButton = findViewById(R.id.login_button); instanceUrlET = findViewById(R.id.instance_url); @@ -105,30 +106,39 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener info_button.setOnClickListener(infoListener); - if(!connToInternet) { + loginMethod.setOnCheckedChangeListener((group, checkedId) -> { - Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection)); - return; + if(checkedId == R.id.loginToken) { - } + loginUidET.setVisibility(View.GONE); + loginPassword.setVisibility(View.GONE); + otpCode.setVisibility(View.GONE); + otpInfo.setVisibility(View.GONE); + loginTokenCode.setVisibility(View.VISIBLE); - loginMethod.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(RadioGroup group, int checkedId) { - if(checkedId == R.id.loginUsernamePassword){ - loginUidET.setVisibility(View.VISIBLE); - loginPassword.setVisibility(View.VISIBLE); - otpCode.setVisibility(View.VISIBLE); - otpInfo.setVisibility(View.VISIBLE); - loginTokenCode.setVisibility(View.GONE); - } else { - loginUidET.setVisibility(View.GONE); - loginPassword.setVisibility(View.GONE); - otpCode.setVisibility(View.GONE); - otpInfo.setVisibility(View.GONE); - loginTokenCode.setVisibility(View.VISIBLE); - } } + else { + + loginUidET.setVisibility(View.VISIBLE); + loginPassword.setVisibility(View.VISIBLE); + otpCode.setVisibility(View.VISIBLE); + otpInfo.setVisibility(View.VISIBLE); + loginTokenCode.setVisibility(View.GONE); + + } + + }); + + networkMonitor.onInternetStateListener(isAvailable -> { + + if(isAvailable) { + enableProcessButton(); + } + else { + disableProcessButton(); + Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection)); + } + }); //login_button.setOnClickListener(this); diff --git a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java index 3259bbbf..ae249f77 100644 --- a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java @@ -270,17 +270,18 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF case 4: // pull requests fragment = new PullRequestsFragment(); break; - case 5: // milestones - return MilestonesFragment.newInstance(repoOwner, repoName); - case 6: // labels - return LabelsFragment.newInstance(repoOwner, repoName); - case 7: // branches + case 5: // branches return BranchesFragment.newInstance(repoOwner, repoName); - case 8: // releases + case 6: // releases return ReleasesFragment.newInstance(repoOwner, repoName); + case 7: // milestones + return MilestonesFragment.newInstance(repoOwner, repoName); + case 8: // labels + return LabelsFragment.newInstance(repoOwner, repoName); case 9: // collaborators return CollaboratorsFragment.newInstance(repoOwner, repoName); } + assert fragment != null; return fragment; } diff --git a/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java index cd88823c..ac4e67a3 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java @@ -57,7 +57,7 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter" + mCtx.getResources().getString(R.string.commitLinkBranchesTab) + " ")); - holder.branchCommitHash.setMovementMethod(LinkMovementMethod.getInstance()); - } @Override diff --git a/app/src/main/java/org/mian/gitnex/adapters/ClosedIssuesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ClosedIssuesAdapter.java index 1360a78a..556fcb0b 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ClosedIssuesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ClosedIssuesAdapter.java @@ -58,7 +58,7 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter LayoutInflater inflater = LayoutInflater.from(context); if(viewType == TYPE_LOAD){ - return new IssuesHolder(inflater.inflate(R.layout.repo_issues_list, parent,false)); + return new IssuesHolder(inflater.inflate(R.layout.list_issues, parent,false)); } else { return new LoadHolder(inflater.inflate(R.layout.row_load,parent,false)); diff --git a/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java index e6200440..d4ec1ed7 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import androidx.annotation.NonNull; -import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.widget.PopupMenu; import androidx.recyclerview.widget.RecyclerView; @@ -123,7 +122,7 @@ public class LabelsAdapter extends RecyclerView.Adapter() { + @SuppressLint("SetTextI18n") @Override public void onNavigateBack(BreadcrumbItem item, int position) { diff --git a/app/src/main/java/org/mian/gitnex/fragments/IssuesOpenFragment.java b/app/src/main/java/org/mian/gitnex/fragments/IssuesOpenFragment.java index cf5100b2..46b70dbc 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/IssuesOpenFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/IssuesOpenFragment.java @@ -51,7 +51,7 @@ public class IssuesOpenFragment extends Fragment { private int pageSize = 1; private TextView noDataIssues; private int resultLimit = 50; - private String requestType = "issues" ; + private String requestType = "issues"; @Nullable @Override diff --git a/app/src/main/java/org/mian/gitnex/helpers/NetworkObserver.java b/app/src/main/java/org/mian/gitnex/helpers/NetworkObserver.java new file mode 100644 index 00000000..6d557f20 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/helpers/NetworkObserver.java @@ -0,0 +1,82 @@ +package org.mian.gitnex.helpers; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; + +/** + * Author M M Arif + */ + +public class NetworkObserver implements LifecycleObserver { + + private ConnectivityManager mConnectivityMgr; + private Context mContext; + private NetworkStateReceiver mNetworkStateReceiver; + + public interface ConnectionStateListener { + void onAvailable(boolean isAvailable); + } + + public NetworkObserver(Context context) { + mContext = context; + mConnectivityMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + ((AppCompatActivity) mContext).getLifecycle().addObserver(this); + } + + + public void onInternetStateListener(ConnectionStateListener listener) { + + mNetworkStateReceiver = new NetworkStateReceiver(listener); + IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(mNetworkStateReceiver, intentFilter); + + } + + + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) + public void onDestroy() { + + ((AppCompatActivity) mContext).getLifecycle().removeObserver(this); + + if (mNetworkStateReceiver != null) { + mContext.unregisterReceiver(mNetworkStateReceiver); + } + + } + + + public class NetworkStateReceiver extends BroadcastReceiver { + + ConnectionStateListener mListener; + + public NetworkStateReceiver(ConnectionStateListener listener) { + mListener = listener; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getExtras() != null) { + NetworkInfo activeNetworkInfo = mConnectivityMgr.getActiveNetworkInfo(); + + if (activeNetworkInfo != null && activeNetworkInfo.getState() == NetworkInfo.State.CONNECTED) { + + mListener.onAvailable(true); // connected + + } else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) { + + mListener.onAvailable(false); // disconnected + + } + } + } + } + +} diff --git a/app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java b/app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java index e00149c3..75cc3cdf 100644 --- a/app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java +++ b/app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java @@ -3,6 +3,7 @@ package org.mian.gitnex.interfaces; import com.google.gson.JsonElement; import org.mian.gitnex.models.AddEmail; import org.mian.gitnex.models.Branches; +import org.mian.gitnex.models.Commits; import org.mian.gitnex.models.ExploreRepositories; import org.mian.gitnex.models.Files; import org.mian.gitnex.models.MergePullRequest; @@ -259,4 +260,7 @@ public interface ApiInterface { @POST("repos/{owner}/{repo}/pulls/{index}/merge") // merge a pull request Call mergePullRequest(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int index, @Body MergePullRequest jsonStr); + + @GET("repos/{owner}/{repo}/commits") // get all commits + Call> getRepositoryCommits(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("page") int page, @Query("sha") String branchName); } diff --git a/app/src/main/java/org/mian/gitnex/items/CommitsItems.java b/app/src/main/java/org/mian/gitnex/items/CommitsItems.java new file mode 100644 index 00000000..bfa2a69f --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/items/CommitsItems.java @@ -0,0 +1,180 @@ +package org.mian.gitnex.items; + +import android.content.Context; +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.widget.TextView; +import androidx.annotation.NonNull; +import com.mikepenz.fastadapter.FastAdapter; +import com.mikepenz.fastadapter.items.AbstractItem; +import org.mian.gitnex.R; +import org.mian.gitnex.helpers.ClickListener; +import org.mian.gitnex.helpers.TimeHelper; +import org.mian.gitnex.util.TinyDB; +import org.ocpsoft.prettytime.PrettyTime; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +/** + * Author M M Arif + */ + +public class CommitsItems extends AbstractItem { + + final private Context ctx; + private String commitTitle; + private String commitHtmlUrl; + private String commitCommitter; + private Date commitDate; + + private boolean isSelectable = true; + + public CommitsItems(Context ctx) { + this.ctx = ctx; + } + + public CommitsItems withNewItems(String commitTitle, String commitHtmlUrl, String commitCommitter, Date commitDate) { + + this.setNewItems(commitTitle, commitHtmlUrl, commitCommitter, commitDate); + return this; + + } + + private void setNewItems(String commitTitle, String commitHtmlUrl, String commitCommitter, Date commitDate) { + + this.commitTitle = commitTitle; + this.commitHtmlUrl = commitHtmlUrl; + this.commitCommitter = commitCommitter; + this.commitDate = commitDate; + + } + + public String getCommitTitle() { + return commitTitle; + } + + private String getCommitHtmlUrl() { + return commitHtmlUrl; + } + + private String getcommitCommitter() { + return commitCommitter; + } + + private Date getcommitDate() { + return commitDate; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public CommitsItems withEnabled(boolean enabled) { + return null; + } + + @Override + public boolean isSelectable() { + return isSelectable; + } + + @Override + public CommitsItems withSelectable(boolean selectable) { + + this.isSelectable = selectable; + return this; + + } + + @Override + public int getType() { + return R.id.commitList; + } + + @Override + public int getLayoutRes() { + return R.layout.list_commits; + } + + @NonNull + @Override + public CommitsItems.ViewHolder getViewHolder(@NonNull View v) { + + return new CommitsItems.ViewHolder(v); + + } + + public class ViewHolder extends FastAdapter.ViewHolder { + + final TinyDB tinyDb = new TinyDB(ctx); + final String locale = tinyDb.getString("locale"); + final String timeFormat = tinyDb.getString("dateFormat"); + + TextView commitTitleVw; + TextView commitCommitterVw; + TextView commitDateVw; + TextView commitHtmlUrlVw; + + public ViewHolder(View itemView) { + + super(itemView); + + commitTitleVw = itemView.findViewById(R.id.commitTitleVw); + commitCommitterVw = itemView.findViewById(R.id.commitCommitterVw); + commitDateVw = itemView.findViewById(R.id.commitDateVw); + commitHtmlUrlVw = itemView.findViewById(R.id.commitHtmlUrlVw); + + } + + @Override + public void bindView(CommitsItems item, @NonNull List payloads) { + + commitTitleVw.setText(item.getCommitTitle()); + commitCommitterVw.setText(ctx.getString(R.string.commitCommittedBy, item.getcommitCommitter())); + + switch (timeFormat) { + case "pretty": { + PrettyTime prettyTime = new PrettyTime(new Locale(locale)); + String createdTime = prettyTime.format(item.getcommitDate()); + commitDateVw.setText(createdTime); + commitDateVw.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(item.getcommitDate()), ctx)); + break; + } + case "normal": { + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + ctx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale)); + String createdTime = formatter.format(item.getcommitDate()); + commitDateVw.setText(createdTime); + break; + } + case "normal1": { + DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + ctx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale)); + String createdTime = formatter.format(item.getcommitDate()); + commitDateVw.setText(createdTime); + break; + } + } + + commitHtmlUrlVw.setText(Html.fromHtml("" + ctx.getResources().getString(R.string.viewInBrowser) + " ")); + commitHtmlUrlVw.setMovementMethod(LinkMovementMethod.getInstance()); + + } + + @Override + public void unbindView(@NonNull CommitsItems item) { + + commitTitleVw.setText(null); + commitCommitterVw.setText(null); + commitDateVw.setText(null); + commitHtmlUrlVw.setText(null); + + } + + } + +} diff --git a/app/src/main/java/org/mian/gitnex/models/Commits.java b/app/src/main/java/org/mian/gitnex/models/Commits.java new file mode 100644 index 00000000..dd64133e --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/models/Commits.java @@ -0,0 +1,258 @@ +package org.mian.gitnex.models; + +import java.util.Date; +import java.util.List; + +/** + * Author M M Arif + */ + +public class Commits { + + private String url; + private String sha; + private String html_url; + private commitObject commit; + private authorObject author; + private committerObject committer; + private List parent; + + public String getUrl() { + return url; + } + + public String getSha() { + return sha; + } + + public String getHtml_url() { + return html_url; + } + + public static class commitObject { + + private String url; + private CommitAuthor author; + private CommitCommitter committer; + private String message; + private CommitTree tree; + + public static class CommitAuthor { + + String name; + String email; + Date date; + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public Date getDate() { + return date; + } + + } + + public static class CommitCommitter { + + String name; + String email; + Date date; + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public Date getDate() { + return date; + } + + } + + public static class CommitTree { + + String url; + String sha; + + public String getUrl() { + return url; + } + + public String getSha() { + return sha; + } + + } + + public String getUrl() { + return url; + } + + public String getMessage() { + return message; + } + + public CommitAuthor getAuthor() { + return author; + } + + public CommitCommitter getCommitter() { + return committer; + } + + public CommitTree getTree() { + return tree; + } + } + + public static class authorObject { + + private int id; + private String login; + private String full_name; + private String email; + private String avatar_url; + private String language; + private Boolean is_admin; + private String last_login; + private String created; + private String username; + + public int getId() { + return id; + } + + public String getLogin() { + return login; + } + + public String getFull_name() { + return full_name; + } + + public String getEmail() { + return email; + } + + public String getAvatar_url() { + return avatar_url; + } + + public String getLanguage() { + return language; + } + + public Boolean getIs_admin() { + return is_admin; + } + + public String getLast_login() { + return last_login; + } + + public String getCreated() { + return created; + } + + public String getUsername() { + return username; + } + } + + public static class committerObject { + + private int id; + private String login; + private String full_name; + private String email; + private String avatar_url; + private String language; + private Boolean is_admin; + private String last_login; + private String created; + private String username; + + public int getId() { + return id; + } + + public String getLogin() { + return login; + } + + public String getFull_name() { + return full_name; + } + + public String getEmail() { + return email; + } + + public String getAvatar_url() { + return avatar_url; + } + + public String getLanguage() { + return language; + } + + public Boolean getIs_admin() { + return is_admin; + } + + public String getLast_login() { + return last_login; + } + + public String getCreated() { + return created; + } + + public String getUsername() { + return username; + } + + } + + public static class parentObject { + + private String url; + private String sha; + + public String getUrl() { + return url; + } + + public String getSha() { + return sha; + } + } + + public commitObject getCommit() { + return commit; + } + + public authorObject getAuthor() { + return author; + } + + public committerObject getCommitter() { + return committer; + } + + public List getParent() { + return parent; + } + +} + + + diff --git a/app/src/main/res/layout/activity_add_collaborator_to_repository.xml b/app/src/main/res/layout/activity_add_collaborator_to_repository.xml index c0112fc8..d55cc514 100644 --- a/app/src/main/res/layout/activity_add_collaborator_to_repository.xml +++ b/app/src/main/res/layout/activity_add_collaborator_to_repository.xml @@ -6,8 +6,10 @@ android:background="?attr/primaryBackgroundColor"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_create_issue.xml b/app/src/main/res/layout/activity_create_issue.xml index edcc5a29..b9bb3f5e 100644 --- a/app/src/main/res/layout/activity_create_issue.xml +++ b/app/src/main/res/layout/activity_create_issue.xml @@ -7,8 +7,10 @@ android:background="?attr/primaryBackgroundColor"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:layout_height="wrap_content" + android:theme="@style/Widget.AppCompat.SearchView"> + android:theme="@style/Widget.AppCompat.SearchView"> - + + @@ -129,7 +130,8 @@ android:textColorHint="?attr/hintColor" android:textColorHighlight="?attr/hintColor" android:hint="@string/userName" - android:inputType="text" /> + android:inputType="text" + android:visibility="gone" /> + android:inputType="textPassword" + android:visibility="gone" /> + android:inputType="number" + android:visibility="gone" /> + android:visibility="visible" /> + android:gravity="end" + android:visibility="gone" />