Merge branch '43-file-browser' of mmarif/GitNex into master

This commit is contained in:
M M Arif 2019-10-07 06:32:42 +00:00 committed by Gitea
commit 84438b740a
58 changed files with 1187 additions and 123 deletions

View File

@ -6,8 +6,8 @@ android {
applicationId "org.mian.gitnex"
minSdkVersion 21
targetSdkVersion 28
versionCode 60
versionName "2.1.0"
versionCode 63
versionName "2.1.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@ -24,7 +24,7 @@ android {
dependencies {
def lifecycle_version = "2.2.0-alpha05"
final def markwon_version = "4.1.1"
final def markwon_version = "4.1.1"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0'

View File

@ -11,8 +11,11 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activities.NewFileActivity"
android:name=".activities.FileViewActivity"
android:theme="@style/AppTheme.NoActionBar"></activity>
<activity
android:name=".activities.NewFileActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.RepoWatchersActivity"
android:theme="@style/AppTheme.NoActionBar" />
@ -64,8 +67,8 @@
<activity android:name=".activities.NewOrganizationActivity" />
<activity android:name=".activities.OpenRepoInBrowserActivity" />
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@ -0,0 +1,147 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class FileViewActivity extends AppCompatActivity {
private View.OnClickListener onClickListener;
private TextView singleFileContents;
final Context ctx = this;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_view);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ImageView closeActivity = findViewById(R.id.close);
singleFileContents = findViewById(R.id.singleFileContents);
singleFileContents.setVisibility(View.GONE);
mProgressBar = findViewById(R.id.progress_bar);
String singleFileName = getIntent().getStringExtra("singleFileName");
TextView toolbar_title = findViewById(R.id.toolbar_title);
toolbar_title.setText(singleFileName);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
if(connToInternet) {
getSingleFileContents(instanceUrl, instanceToken, repoOwner, repoName, singleFileName);
}
else {
Toasty.info(getApplicationContext(), getString(R.string.checkNetConnection));
}
}
private void getSingleFileContents(String instanceUrl, String token, final String owner, String repo, final String filename) {
Call<Files> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getSingleFileContents(token, owner, repo, filename);
call.enqueue(new Callback<Files>() {
@Override
public void onResponse(@NonNull Call<Files> call, @NonNull retrofit2.Response<Files> response) {
if (response.code() == 200) {
AppUtil appUtil = new AppUtil();
assert response.body() != null;
if(!response.body().getContent().equals("")) {
singleFileContents.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
singleFileContents.setText(appUtil.decodeBase64(response.body().getContent()));
}
else {
singleFileContents.setText("");
mProgressBar.setVisibility(View.GONE);
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<Files> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
getIntent().removeExtra("singleFileName");
finish();
}
};
}
}

View File

@ -354,9 +354,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
userAvatar = hView.findViewById(R.id.userAvatar);
if (!Objects.requireNonNull(userDetails).getAvatar().equals("")) {
Picasso.get().load(userDetails.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(userAvatar);
Picasso.get().load(userDetails.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar);
} else {
userAvatar.setImageResource(R.mipmap.ic_launcher_round);
userAvatar.setImageResource(R.mipmap.app_logo_round);
}
userFullName = hView.findViewById(R.id.userFullname);

View File

@ -26,6 +26,7 @@ import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BranchesFragment;
import org.mian.gitnex.fragments.ClosedIssuesFragment;
import org.mian.gitnex.fragments.CollaboratorsFragment;
import org.mian.gitnex.fragments.FilesFragment;
import org.mian.gitnex.fragments.IssuesFragment;
import org.mian.gitnex.fragments.LabelsFragment;
import org.mian.gitnex.fragments.MilestonesFragment;
@ -87,9 +88,9 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
if(!tinyDb.getString("issuesCounter").isEmpty()) {
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
}
Objects.requireNonNull(tabLayout.getTabAt(1)).setCustomView(tabHeader);
Objects.requireNonNull(tabLayout.getTabAt(2)).setCustomView(tabHeader);
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(1);
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(2);
ColorStateList textColor = tabLayout.getTabTextColors();
assert tabOpenIssues != null;
TextView openIssueTabView = Objects.requireNonNull(tabOpenIssues.getCustomView()).findViewById(R.id.counterBadgeText);
@ -199,21 +200,23 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
switch (position) {
case 0: // information
return RepoInfoFragment.newInstance(repoOwner, repoName);
case 1: // issues
case 1: // files
return FilesFragment.newInstance(repoOwner, repoName);
case 2: // issues
fragment = new IssuesFragment();
break;
case 2: // closed issues
case 3: // closed issues
fragment = new ClosedIssuesFragment();
break;
case 3: // milestones
case 4: // milestones
return MilestonesFragment.newInstance(repoOwner, repoName);
case 4: // labels
case 5: // labels
return LabelsFragment.newInstance(repoOwner, repoName);
case 5: // branches
case 6: // branches
return BranchesFragment.newInstance(repoOwner, repoName);
case 6: // releases
case 7: // releases
return ReleasesFragment.newInstance(repoOwner, repoName);
case 7: // collaborators
case 8: // collaborators
return CollaboratorsFragment.newInstance(repoOwner, repoName);
}
return fragment;
@ -221,7 +224,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
@Override
public int getCount() {
return 8;
return 9;
}
}

View File

@ -0,0 +1,211 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.FileViewActivity;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
/**
* Author M M Arif
*/
public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHolder> implements Filterable {
private List<Files> filesList;
private Context mCtx;
private List<Files> filesListFull;
class FilesViewHolder extends RecyclerView.ViewHolder {
private ImageView fileTypeImage;
private TextView fileName;
private TextView fileType;
private FilesViewHolder(View itemView) {
super(itemView);
fileName = itemView.findViewById(R.id.fileName);
fileTypeImage = itemView.findViewById(R.id.fileImage);
fileType = itemView.findViewById(R.id.fileType);
//ImageView filesDropdownMenu = itemView.findViewById(R.id.filesDropdownMenu);
fileName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
TinyDB tinyDb = new TinyDB(context);
if(fileType.getText().toString().equals("file")) {
Intent intent = new Intent(context, FileViewActivity.class);
intent.putExtra("singleFileName", fileName.getText().toString());
context.startActivity(intent);
}
else if(fileType.getText().toString().equals("dir")) {
//tinyDb.putString("filesDir", fileName.getText().toString());
Toasty.info(context, context.getString(R.string.filesDirNotSupportedYet));
}
else {
Toasty.info(context, context.getString(R.string.filesGenericError));
}
}
});
/*filesDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.files_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.deleteFile:
Intent intent = new Intent(context, DeleteFileActivity.class);
intent.putExtra("repoFullNameForDeleteFile", fullName.getText());
context.startActivity(intent);
break;
case R.id.editFile:
Intent intentW = new Intent(context, EditFileActivity.class);
intentW.putExtra("repoFullNameForEditFile", fullName.getText());
context.startActivity(intentW);
break;
case R.id.openInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenFileInBrowserActivity.class);
intentOpenInBrowser.putExtra("fileFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});*/
}
}
public FilesAdapter(Context mCtx, List<Files> filesListMain) {
this.mCtx = mCtx;
this.filesList = filesListMain;
filesListFull = new ArrayList<>(filesList);
}
@NonNull
@Override
public FilesAdapter.FilesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.files_list, parent, false);
return new FilesAdapter.FilesViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull FilesAdapter.FilesViewHolder holder, int position) {
Files currentItem = filesList.get(position);
holder.fileType.setText(currentItem.getType());
holder.fileName.setText(currentItem.getName());
if(currentItem.getType().equals("file")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_file_new));
}
else if(currentItem.getType().equals("dir")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_folder_24));
}
else {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_question_mark_24));
}
}
@Override
public int getItemCount() {
return filesList.size();
}
@Override
public Filter getFilter() {
return filesFilter;
}
private Filter filesFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Files> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(filesListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Files item : filesListFull) {
if (item.getName().toLowerCase().contains(filterPattern) || item.getPath().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filesList.clear();
filesList.addAll((List) results.values);
notifyDataSetChanged();
}
};
}

View File

@ -237,6 +237,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
if (currentItem.getOpen_issues() == 0) {
holder.msProgress.setProgress(100);
holder.msProgress.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.milestoneCompletion, 100), mCtx));
}
else {
int msCompletion = 100 * currentItem.getClosed_issues() / (currentItem.getOpen_issues() + currentItem.getClosed_issues());

View File

@ -179,9 +179,14 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.imageMy);
} else {
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.imageMy);
} else {
holder.imageMy.setImageDrawable(drawable);
}
}
else {
holder.imageMy.setImageDrawable(drawable);
}

View File

@ -181,9 +181,14 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}

View File

@ -180,9 +180,14 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}

View File

@ -180,9 +180,14 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}

View File

@ -0,0 +1,225 @@
package org.mian.gitnex.fragments;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.FilesAdapter;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.FilesViewModel;
import java.util.List;
import java.util.Objects;
/**
* Author M M Arif
*/
public class FilesFragment extends Fragment {
private ProgressBar mProgressBar;
private FilesAdapter adapter;
private RecyclerView mRecyclerView;
private TextView noDataFiles;
private LinearLayout filesFrame;
private static String repoNameF = "param2";
private static String repoOwnerF = "param1";
private boolean initialLoad = true;
private String repoName;
private String repoOwner;
private OnFragmentInteractionListener mListener;
public FilesFragment() {
}
public static FilesFragment newInstance(String param1, String param2) {
FilesFragment fragment = new FilesFragment();
Bundle args = new Bundle();
args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
repoName = getArguments().getString(repoNameF);
repoOwner = getArguments().getString(repoOwnerF);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_files, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
noDataFiles = v.findViewById(R.id.noDataFiles);
filesFrame = v.findViewById(R.id.filesFrame);
final SwipeRefreshLayout swipeRefresh = v.findViewById(R.id.pullToRefresh);
mRecyclerView = v.findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
String filesDirDB = tinyDb.getString("filesDir");
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
mProgressBar = v.findViewById(R.id.progress_bar);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefresh.setRefreshing(false);
FilesViewModel.loadFilesList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
}
}, 200);
}
});
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
return v;
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel.getFilesList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Files>>() {
@Override
public void onChanged(@Nullable List<Files> filesListMain) {
adapter = new FilesAdapter(getContext(), filesListMain);
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
}
private void fetchDataAsyncSub(String instanceUrl, String instanceToken, String owner, String repo, String filesDir) {
FilesViewModel filesModel2 = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel2.getFilesList2(instanceUrl, instanceToken, owner, repo, filesDir).observe(this, new Observer<List<Files>>() {
@Override
public void onChanged(@Nullable List<Files> filesListMain2) {
adapter = new FilesAdapter(getContext(), filesListMain2);
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext()));
inflater.inflate(R.menu.search_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
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.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
}
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}

View File

@ -247,7 +247,7 @@ public class RepoInfoFragment extends Fragment {
repoRepoUrlInfo.setText(repoInfo.getHtml_url());
repoForksCountInfo.setText(repoInfo.getForks_count());
if(repoInfo.getHas_issues()) {
if(repoInfo.getHas_issues() != null) {
tinyDb.putBoolean("hasIssues", repoInfo.getHas_issues());
}
else {

View File

@ -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.Files;
import org.mian.gitnex.models.NewFile;
import org.mian.gitnex.models.UpdateIssueAssignee;
import org.mian.gitnex.models.UpdateIssueState;
@ -214,4 +215,13 @@ public interface ApiInterface {
@POST("repos/{owner}/{repo}/contents/{file}") // create new file
Call<JsonElement> createNewFile(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("file") String fileName, @Body NewFile jsonStr);
@GET("repos/{owner}/{repo}/contents") // get all the files and dirs of a repository
Call<List<Files>> getFiles(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/{owner}/{repo}/contents/{file}") // get single file contents
Call<Files> getSingleFileContents(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("file") String file);
@GET("repos/{owner}/{repo}/contents/{fileDir}") // get all the sub files and dirs of a repository
Call<List<Files>> getDirFiles(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("fileDir") String fileDir);
}

View File

@ -0,0 +1,74 @@
package org.mian.gitnex.models;
/**
* Author M M Arif
*/
public class Files {
private String name;
private String path;
private String sha;
private String type;
private int size;
private String encoding;
private String content;
private String target;
private String url;
private String html_url;
private String git_url;
private String download_url;
private String submodule_git_url;
public String getName() {
return name;
}
public String getPath() {
return path;
}
public String getSha() {
return sha;
}
public String getType() {
return type;
}
public int getSize() {
return size;
}
public String getEncoding() {
return encoding;
}
public String getContent() {
return content;
}
public String getTarget() {
return target;
}
public String getUrl() {
return url;
}
public String getHtml_url() {
return html_url;
}
public String getGit_url() {
return git_url;
}
public String getDownload_url() {
return download_url;
}
public String getSubmodule_git_url() {
return submodule_git_url;
}
}

View File

@ -0,0 +1,112 @@
package org.mian.gitnex.viewmodels;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.models.Files;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class FilesViewModel extends ViewModel {
private static MutableLiveData<List<Files>> filesList;
private static MutableLiveData<List<Files>> filesList2;
public LiveData<List<Files>> getFilesList(String instanceUrl, String token, String owner, String repo) {
filesList = new MutableLiveData<>();
loadFilesList(instanceUrl, token, owner, repo);
return filesList;
}
public static void loadFilesList(String instanceUrl, String token, String owner, String repo) {
Call<List<Files>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getFiles(token, owner, repo);
call.enqueue(new Callback<List<Files>>() {
@Override
public void onResponse(@NonNull Call<List<Files>> call, @NonNull Response<List<Files>> response) {
Collections.sort(response.body(), new Comparator<Files>() {
@Override
public int compare(Files byType1, Files byType2) {
return byType1.getType().compareTo(byType2.getType());
}
});
if (response.isSuccessful()) {
filesList.postValue(response.body());
} else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Files>> call, Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
public LiveData<List<Files>> getFilesList2(String instanceUrl, String token, String owner, String repo, String filesDir) {
filesList = new MutableLiveData<>();
loadFilesList2(instanceUrl, token, owner, repo, filesDir);
return filesList;
}
public static void loadFilesList2(String instanceUrl, String token, String owner, String repo, String filesDir) {
Call<List<Files>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getDirFiles(token, owner, repo, filesDir);
call.enqueue(new Callback<List<Files>>() {
@Override
public void onResponse(@NonNull Call<List<Files>> call, @NonNull Response<List<Files>> response) {
Collections.sort(response.body(), new Comparator<Files>() {
@Override
public int compare(Files byType1, Files byType2) {
return byType1.getType().compareTo(byType2.getType());
}
});
if (response.isSuccessful()) {
filesList.postValue(response.body());
} else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Files>> call, Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
}

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="512dp"
android:height="512dp"
android:viewportWidth="16"
android:viewportHeight="16"
tools:ignore="VectorRaster">
<path
android:fillColor="#FFFFFF"
android:pathData="m13.707,3.293 l-3,-3c-0.1875,-0.1875 -0.4419,-0.293 -0.707,-0.293h-7c-0.5522,0 -1,0.4478 -1,1v14c0,0.5527 0.4478,1 1,1h10c0.5522,0 1,-0.4473 1,-1v-11c0,-0.2651 -0.1055,-0.5195 -0.293,-0.707zM8,12h-3v-2h3zM11,9h-6v-2h6zM11,4c-0.5523,0 -1,-0.4478 -1,-1v-2l3,3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
</vector>

View File

@ -4,8 +4,8 @@
<item
android:id="@android:id/background"
android:top="4dp"
android:bottom="4dp"
android:top="2dp"
android:bottom="2dp"
android:right="1dp"
android:left="1dp">
<shape>
@ -16,12 +16,12 @@
<item
android:id="@android:id/progress"
android:top="1dp"
android:bottom="1dp"
android:top="3dp"
android:bottom="3dp"
android:left="1dp"
android:right="1dp">
<scale android:scaleWidth="100%" android:scaleHeight="80%">
<scale android:scaleWidth="100%">
<shape>
<corners android:radius="15dp" />
</shape>

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/colorPrimary">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
tools:ignore="UnusedAttribute">
<ImageView
android:id="@+id/close"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="15dp"
android:layout_marginLeft="15dp"
android:gravity="center_vertical"
android:contentDescription="@string/close"
android:src="@drawable/ic_close" />
<TextView
android:id="@+id/toolbar_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/defaultFilename"
android:textColor="@color/white"
android:maxLines="1"
android:textSize="20sp" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_marginTop="50dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/toastBackground">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="UselessParent">
<TextView
android:id="@+id/singleFileContents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textSize="16sp"
android:padding="15dp"
/>
</ScrollView>
</LinearLayout>
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
android:visibility="visible" />
</RelativeLayout>

View File

@ -22,7 +22,7 @@
android:layout_marginBottom="20dp"
android:baselineAligned="false"
android:contentDescription="@string/app_name"
android:src="@mipmap/app_logo_round" />
android:src="@mipmap/app_logo" />
<LinearLayout
android:layout_width="match_parent"

View File

@ -39,6 +39,12 @@
android:layout_height="wrap_content"
android:text="@string/tab_text_info" />
<com.google.android.material.tabs.TabItem
android:id="@+id/tabItemFiles"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tab_text_files" />
<com.google.android.material.tabs.TabItem
android:id="@+id/tabItem2_issues"
android:layout_width="wrap_content"

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayoutFilesFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:fitsSystemWindows="true"
android:orientation="vertical"
android:layout_margin="10dp"
android:theme="@style/AppTheme"
android:background="@color/backgroundColor"
tools:context=".activities.MainActivity">
<TextView
android:id="@+id/fileType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<ImageView
android:id="@+id/fileImage"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="15dp"
android:contentDescription="@string/repoContentAvatar"
android:src="@drawable/ic_android" />
<LinearLayout
android:id="@+id/infoSection"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/fileImage"
android:orientation="horizontal">
<TextView
android:id="@+id/fileName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".80"
android:layout_marginBottom="0dp"
android:text="@string/defaultFilename"
android:textColor="@color/white"
android:textSize="16sp" />
<ImageView
android:id="@+id/filesDropdownMenu"
android:layout_width="0dp"
android:layout_weight=".10"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:scaleType="fitEnd"
android:visibility="gone"
android:src="@drawable/ic_dotted_menu_horizontal"
android:contentDescription="@string/menuContentDesc" />
</LinearLayout>
</RelativeLayout>

View File

@ -25,7 +25,7 @@
android:layout_marginTop="20dp"
android:baselineAligned="false"
android:contentDescription="@string/logo"
android:src="@mipmap/app_logo_round" />
android:src="@mipmap/app_logo" />
<TextView
android:id="@+id/appName"

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".activities.RepoDetailActivity">
<LinearLayout
android:id="@+id/filesFrame"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/fileBrowserBreadcrumb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:textColor="@color/lightGray"
android:text="@string/filesBreadcrumb" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/pullToRefresh"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:padding="4dp"
android:scrollbars="vertical"
/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/noDataFiles"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:gravity="center"
android:text="@string/noDataFilesTab"
android:textColor="@color/white"
android:textSize="20sp"
android:visibility="gone" />
</LinearLayout>
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="visible" />
</LinearLayout>

View File

@ -67,7 +67,7 @@
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="82"
android:layout_weight="80"
android:progress="50"
android:layout_marginTop="2dp"
android:progressDrawable="@drawable/progress_bar"

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -114,6 +114,7 @@
<string name="infoTabRepoForksCount">Anzahl an Forks</string>
<string name="infoTabRepoCreatedAt">Erstellt</string>
<string name="infoTabRepoUpdatedAt">Letzte Aktualisierung</string>
<string name="timeAtText">um</string>
<string name="createdText">Erstellt\u0020</string>
<string name="dueDateText">Fälligkeitsdatum </string>
@ -135,6 +136,7 @@
<string name="commentSuccess">Kommentar gepostet</string>
<string name="commentError">Etwas ist schief gelaufen. Bitte versuche es erneut</string>
<string name="generalImgContentText">Benutzerbild</string>
<string name="noDataMilestonesTab">Kein Meilenstein gefunden!</string>
<string name="commitAuthor">Commit Autor: %1$s</string>
<string name="commitHash">Commit Hash \n%1$s%2$s</string>
@ -370,11 +372,16 @@
<string name="copyIssueUrl">Issue Link kopieren</string>
<string name="copyIssueUrlToastMsg">Issue Link in Zwischenablage kopiert</string>
<string name="milestoneCompletion">%1$d\uFF05 abgeschlossen</string>
<!-- files -->
<string name="noDataFilesTab">Keine Dateien gefunden</string>
<!-- files -->
<string name="noDataFilesTab">Keine Dateien gefunden</string>
<string name="filesDirNotSupportedYet">Ordner sind noch nicht unterstützt</string>
<string name="filesGenericError">Datei kann nicht angezeigt werden, da die API einen Fehler meldet</string>
<string name="filesBreadcrumb">Wurzel</string>
<!-- generic copy -->
<string name="okButton">OK</string>
<string name="doneButton">Fertig</string>

View File

@ -114,6 +114,8 @@
<string name="infoTabRepoForksCount">Forks Count</string>
<string name="infoTabRepoCreatedAt">Created</string>
<string name="infoTabRepoUpdatedAt">Last Updated</string>
<string name="infoTabRepoDefaultBranchText">master</string>
<string name="timeAtText">à</string>
<string name="createdText">Created\u0020</string>
<string name="dueDateText">Due Date</string>
@ -135,6 +137,7 @@
<string name="commentSuccess">Comment posted</string>
<string name="commentError">Something went wrong, please try again</string>
<string name="generalImgContentText">IMG</string>
<string name="noDataMilestonesTab">No Milestone found!</string>
<string name="commitAuthor">Commit author : %1$s</string>
<string name="commitHash">Commit hash \n%1$s%2$s</string>
@ -370,11 +373,16 @@
<string name="copyIssueUrl">Copier l Issue URL</string>
<string name="copyIssueUrlToastMsg">Issue URL copied to clipboard</string>
<string name="milestoneCompletion">%1$d\uFF05 terminé</string>
<!-- files -->
<string name="noDataFilesTab">Aucun fichier trouvé</string>
<!-- files -->
<string name="noDataFilesTab">Aucun fichier trouvé</string>
<string name="filesDirNotSupportedYet">Directory browsing is not supported yet</string>
<string name="filesGenericError">Sorry this file cannot be viewed as API returned an error</string>
<string name="filesBreadcrumb">Root</string>
<!-- generic copy -->
<string name="okButton">OK</string>
<string name="doneButton">Done</string>

View File

@ -114,6 +114,8 @@
<string name="infoTabRepoForksCount">Кол-во форков</string>
<string name="infoTabRepoCreatedAt">Создан</string>
<string name="infoTabRepoUpdatedAt">Последнее обновление</string>
<string name="infoTabRepoDefaultBranchText">master</string>
<string name="timeAtText">в</string>
<string name="createdText">Создано\u0020</string>
<string name="dueDateText">Дата исполнения</string>
@ -135,6 +137,7 @@
<string name="commentSuccess">Комментарий отправлен!</string>
<string name="commentError">Что-то пошло не так. Пожалуйста, попытайтесь еще раз.</string>
<string name="generalImgContentText">Аватар</string>
<string name="noDataMilestonesTab">Вех не обнаружено</string>
<string name="commitAuthor">Автор коммита: %1$s</string>
<string name="commitHash">Хеш коммита \n%1$s%2$s</string>
@ -370,11 +373,16 @@
<string name="copyIssueUrl">Copy Issue URL</string>
<string name="copyIssueUrlToastMsg">Issue URL copied to clipboard</string>
<string name="milestoneCompletion">%1$d\uFF05 выполненный</string>
<!-- files -->
<string name="noDataFilesTab">Файлов не найдено</string>
<!-- files -->
<string name="noDataFilesTab">Файлов не найдено</string>
<string name="filesDirNotSupportedYet">Directory browsing is not supported yet</string>
<string name="filesGenericError">Sorry this file cannot be viewed as API returned an error</string>
<string name="filesBreadcrumb">Root</string>
<!-- generic copy -->
<string name="okButton">OK</string>
<string name="doneButton">Готово</string>

View File

@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.com-->
<resources>
<!-- These strings does not need translations -->
<!-- These strings does not need translations -->
<!-- links text -->
<!-- links text -->
<!-- menu items -->
<string name="navMyRepos">我的仓库</string>
<string name="navStarredRepos">已点赞</string>
@ -66,7 +62,6 @@
<string name="logo">Login to Gitea</string>
<string name="urlInfoTooltip">1- Choose the correct protocol(https or http). \n2- Enter Gitea url e.g: try.gitea.io. \n3- If you have enabled 2FA for your account, enter the code in the OTP Code field. \n4- For HTTP basic auth use USERNAME@DOMAIN.COM in the URL field.</string>
<string name="loginFailed">Wrong username/password</string>
<string name="protocolDelimiter">://</string>
<string name="protocolError">It is not recommended to use HTTP protocol unless you are testing on local network.</string>
<string name="malformedJson">Malformed JSON was received. Server response was not successful.</string>
<string name="emptyFieldURL">Instance URL is required</string>
@ -93,13 +88,11 @@
<string name="orgContentAvatar">Org</string>
<string name="repoContentAvatar">Repo</string>
<string name="privateAvatar">Pri</string>
<string name="repoStars">12345</string>
<string name="repoWatchers">98324</string>
<string name="repoIssues">54321</string>
<string name="removeContent">Remove</string>
<string name="genericApiStatusError">Instance has returned an error. Code\u0020</string>
<string name="title_activity_repo_detail">RepoDetailActivity</string>
<string name="tab_text_info">Details</string>
<string name="tab_text_files">Files</string>
<string name="tab_text_issues">Open Issues</string>
<string name="tabItemCloseIssues">Closed Issues</string>
<string name="tab_text_ml">Milestones</string>
@ -121,12 +114,7 @@
<string name="infoTabRepoForksCount">Forks</string>
<string name="infoTabRepoCreatedAt">Created</string>
<string name="infoTabRepoUpdatedAt">Last Updated</string>
<string name="infoTabRepoDummyTime">2018&#8211;10&#8211;30 08:25:25</string>
<string name="infoTabRepoBlank">&#8230;</string>
<string name="infoTabRepoZero">0</string>
<string name="infoTabRepoDefaultBranchText">master</string>
<string name="timeAtText">at</string>
<string name="hash">#</string>
<string name="createdText">Opened\u0020</string>
<string name="dueDateText">Due Date</string>
<string name="issueStatusTextOpen">Status: open</string>
@ -138,7 +126,6 @@
<string name="issueTypeIssue">Type: Issue</string>
<string name="issueTypePullRequest">Type: Pull Request</string>
<string name="issueCommenter">Commenter:\u0020</string>
<string name="issueTitleWithId">#%1$d %2$s</string>
<string name="issueMilestone">Milestone %1$s</string>
<string name="dueDate">Due %1$s</string>
<string name="createdTime">Opened %1$s</string>
@ -148,7 +135,6 @@
<string name="commentSuccess">Comment posted</string>
<string name="commentError">Something went wrong, please try again</string>
<string name="generalImgContentText">Avatar</string>
<string name="generalPageTitle">GitNex</string>
<string name="noDataMilestonesTab">No milestones found</string>
<string name="commitAuthor">Commit author: %1$s</string>
<string name="commitHash">Commit hash \n%1$s%2$s</string>
@ -166,7 +152,6 @@
<string name="newMilestoneTitle">Title</string>
<string name="newMilestoneDescription">Description</string>
<string name="newMilestoneDueDate">Due Date</string>
<string name="setDueDate">%1$d-%2$d-%3$d</string>
<string name="milestoneNameErrorEmpty">Milestone title is empty</string>
<string name="milestoneNameErrorInvalid">Milestone title is not valid. [a&#8211;z A&#8211;Z 0&#8211;9 &#8211; _]</string>
<string name="milestoneDescError">Milestone description exceeds the max 255 characters limit</string>
@ -185,8 +170,6 @@
<string name="newIssueDueDateTitle">Due Date</string>
<string name="newIssueMilestoneTitle">Milestone</string>
<string name="newIssueLabelsTitle">Labels</string>
<string name="spinnerMilestoneText">%1$s [%2$s]</string>
<string name="dialogAssignessText">%1$s - @%2$s</string>
<string name="issueTitleEmpty">Issue title is empty</string>
<string name="issueDescriptionEmpty">Issue description is empty</string>
<string name="issueCreated">New issue created successfully</string>
@ -211,15 +194,15 @@
<string name="settingsHomeScreenSelectedText">My Repositories</string>
<string name="settingshomeScreenSelectorDialogTitle">Select Home Screen</string>
<!-- settings -->
<string name="noMoreData">No more data available.</string>
<string name="noMoreData">No more data available</string>
<string name="createLabel">New Label</string>
<string name="menuTitleText">Repo Menu</string>
<string name="labelName">Label Name</string>
<string name="labelColor">Label Color</string>
<string name="labelEmptyError">Label name is empty.</string>
<string name="labelNameError">Label name is not valid.</string>
<string name="labelEmptyError">Label name is empty</string>
<string name="labelNameError">Label name is not valid</string>
<string name="labelCreated">Label created.</string>
<string name="labelGeneralError">Something went wrong, please try again.</string>
<string name="labelGeneralError">Something went wrong, please try again</string>
<string name="labelUpdated">Label updated.</string>
<string name="noDataLabelsTab">No labels found</string>
<string name="labelMenuContentDesc">Desc</string>
@ -232,7 +215,7 @@
<!-- credits - this part does not need translation -->
<!-- credits - this part does not need translation -->
<string name="alertDialogTokenRevokedTitle">Authorization Error</string>
<string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR your are not allowed to see these contents. In case of revoked Token, please logout and login again.</string>
<string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR your are not allowed to see these contents. In case of revoked Token, please logout and login again</string>
<string name="alertDialogTokenRevokedCopyNegativeButton">Cancel</string>
<string name="alertDialogTokenRevokedCopyPositiveButton">Logout</string>
<string name="labelDeleteTitle">Delete\u0020</string>
@ -258,16 +241,16 @@
<string name="newTeamDesc">Description</string>
<string name="newTeamPermission">Permission</string>
<string name="newTeamAccessControls">Access Controls</string>
<string name="newTeamPermissionRead">Members can view and clone team repositories.</string>
<string name="newTeamPermissionWrite">Members can read and push to team repositories.</string>
<string name="newTeamPermissionAdmin">Members can pull and push to team repositories and add collaborators to them.</string>
<string name="teamNameEmpty">Please enter team name.</string>
<string name="teamNameError">Team name should contain only alphanumeric, dash (-), underscore (_) and dot (.) characters.</string>
<string name="teamPermissionEmpty">Please select permission.</string>
<string name="teamDescError">Team description have illegal characters.</string>
<string name="teamDescLimit">Team description have more than 100 characters.</string>
<string name="teamCreated">Team created successfully.</string>
<string name="teamCreatedError">Something went wrong, please try again.</string>
<string name="newTeamPermissionRead">Members can view and clone team repositories</string>
<string name="newTeamPermissionWrite">Members can read and push to team repositories</string>
<string name="newTeamPermissionAdmin">Members can pull and push to team repositories and add collaborators to them</string>
<string name="teamNameEmpty">Please enter team name</string>
<string name="teamNameError">Team name should contain only alphanumeric, dash (-), underscore (_) and dot (.) characters</string>
<string name="teamPermissionEmpty">Please select permission</string>
<string name="teamDescError">Team description have illegal characters</string>
<string name="teamDescLimit">Team description have more than 100 characters</string>
<string name="teamCreated">Team created successfully</string>
<string name="teamCreatedError">Something went wrong, please try again</string>
<!-- create team -->
<!-- edit comment -->
<string name="editCommentTitle">Edit Comment</string>
@ -291,8 +274,8 @@
<string name="profileEmailTitle">Email Address</string>
<string name="emailAddedText">New email added successfully.</string>
<string name="emailErrorEmpty">Email address is empty.</string>
<string name="emailErrorInvalid">Email address is not valid.</string>
<string name="emailErrorInUse">Email address is already in use.</string>
<string name="emailErrorInvalid">Email address is not valid</string>
<string name="emailErrorInUse">Email address is already in use</string>
<string name="emailTypeText">Primary</string>
<string name="profileTabEmails">Emails</string>
<!-- profile section -->
@ -387,6 +370,11 @@
<string name="copyIssueUrl">Copy Issue URL</string>
<string name="copyIssueUrlToastMsg">Issue URL copied to clipboard</string>
<string name="milestoneCompletion">%1$d\uFF05 completed</string>
<!-- files -->
<string name="noDataFilesTab">No files found</string>
<string name="filesDirNotSupportedYet">Directory browsing is not supported yet</string>
<string name="filesGenericError">Sorry this file cannot be viewed as API returned an error</string>
<string name="filesBreadcrumb">Root</string>
<!-- generic copy -->
<string name="okButton">OK</string>
<string name="doneButton">Done</string>
@ -408,6 +396,5 @@
<string name="locationText">Location</string>
<string name="characters255Limit">Max 255 characters</string>
<string name="emptyFields">All fields are required</string>
<string name="translateText">Translate GitNex with Crowdin</string>
<!-- generic copy -->
</resources>

View File

@ -1,5 +1,5 @@
<resources>
<!-- These strings does not need translations -->
<string name="app_name" translatable="false">GitNex</string>
<string name="appAuthor" translatable="false">Developer : M M Arif</string>
<string name="appEmail" translatable="false">gitnex@gitnex.com</string>
@ -14,14 +14,10 @@
<string name="supportLinkPatreon" translatable="false">https://www.patreon.com/mmarif</string>
<string name="appVerBuild" translatable="false">%1$s / build %2$d</string>
<string name="appDesc" translatable="false">GitNex is a free, open-source Android client for Git repository management tool Gitea. GitNex is Licensed under GPLv3.\n\nThanks to all the contributors and sponsors for your generous work and donations.</string>
<string name="corwdinLink" translatable="false">https://crowdin.com/project/gitnex</string>
<!-- These strings does not need translations -->
<!-- links text -->
<string name="appRepoIssuesText" translatable="false">Report issues at Gitea</string>
<string name="supportText" translatable="false">Support the App on Liberapay</string>
<string name="supportTextPatreon" translatable="false">Become a Patreon</string>
<!-- links text -->
<!-- menu items -->
<string name="navMyRepos">My Repositories</string>
@ -92,7 +88,7 @@
<string name="logo">Login to Gitea</string>
<string name="urlInfoTooltip">1- Choose the correct protocol(https or http). \n2- Enter Gitea url e.g: try.gitea.io. \n3- If you have enabled 2FA for your account, enter the code in the OTP Code field. \n4- For HTTP basic auth use USERNAME@DOMAIN.COM in the URL field.</string>
<string name="loginFailed">Wrong username/password</string>
<string name="protocolDelimiter">://</string>
<string name="protocolDelimiter" translatable="false">://</string>
<string name="protocolError">It is not recommended to use HTTP protocol unless you are testing on local network.</string>
<string name="malformedJson">Malformed JSON was received. Server response was not successful.</string>
<string name="emptyFieldURL">Instance URL is required</string>
@ -124,14 +120,15 @@
<string name="orgContentAvatar">Org</string>
<string name="repoContentAvatar">Repo</string>
<string name="privateAvatar">Pri</string>
<string name="repoStars">12345</string>
<string name="repoWatchers">98324</string>
<string name="repoIssues">54321</string>
<string name="repoStars" translatable="false">12345</string>
<string name="repoWatchers" translatable="false">98324</string>
<string name="repoIssues" translatable="false">54321</string>
<string name="removeContent">Remove</string>
<string name="genericApiStatusError">Instance has returned an error. Code\u0020</string>
<string name="title_activity_repo_detail">RepoDetailActivity</string>
<string name="tab_text_info">Details</string>
<string name="tab_text_files">Files</string>
<string name="tab_text_issues">Open Issues</string>
<string name="tabItemCloseIssues">Closed Issues</string>
<string name="tab_text_ml">Milestones</string>
@ -155,13 +152,13 @@
<string name="infoTabRepoForksCount">Forks</string>
<string name="infoTabRepoCreatedAt">Created</string>
<string name="infoTabRepoUpdatedAt">Last Updated</string>
<string name="infoTabRepoDummyTime">2018&#8211;10&#8211;30 08:25:25</string>
<string name="infoTabRepoBlank">&#8230;</string>
<string name="infoTabRepoZero">0</string>
<string name="infoTabRepoDefaultBranchText">master</string>
<string name="infoTabRepoDummyTime" translatable="false">2018&#8211;10&#8211;30 08:25:25</string>
<string name="infoTabRepoBlank" translatable="false">&#8230;</string>
<string name="infoTabRepoZero" translatable="false">0</string>
<string name="infoTabRepoDefaultBranchText" translatable="false">master</string>
<string name="timeAtText">at</string>
<string name="hash">#</string>
<string name="hash" translatable="false">#</string>
<string name="createdText">Opened\u0020</string>
<string name="dueDateText">Due Date</string>
<string name="issueStatusTextOpen">Status: open</string>
@ -173,7 +170,7 @@
<string name="issueTypeIssue">Type: Issue</string>
<string name="issueTypePullRequest">Type: Pull Request</string>
<string name="issueCommenter">Commenter:\u0020</string>
<string name="issueTitleWithId">#%1$d %2$s</string>
<string name="issueTitleWithId" translatable="false">#%1$d %2$s</string>
<string name="issueMilestone">Milestone %1$s</string>
<string name="dueDate">Due %1$s</string>
<string name="createdTime">Opened %1$s</string>
@ -184,7 +181,7 @@
<string name="commentError">Something went wrong, please try again</string>
<string name="generalImgContentText">Avatar</string>
<string name="generalPageTitle">GitNex</string>
<string name="generalPageTitle" translatable="false">GitNex</string>
<string name="noDataMilestonesTab">No milestones found</string>
@ -210,7 +207,7 @@
<string name="newMilestoneTitle">Title</string>
<string name="newMilestoneDescription">Description</string>
<string name="newMilestoneDueDate">Due Date</string>
<string name="setDueDate">%1$d-%2$d-%3$d</string>
<string name="setDueDate" translatable="false">%1$d-%2$d-%3$d</string>
<string name="milestoneNameErrorEmpty">Milestone title is empty</string>
<string name="milestoneNameErrorInvalid">Milestone title is not valid. [a&#8211;z A&#8211;Z 0&#8211;9 &#8211; _]</string>
<string name="milestoneDescError">Milestone description exceeds the max 255 characters limit</string>
@ -230,8 +227,8 @@
<string name="newIssueDueDateTitle">Due Date</string>
<string name="newIssueMilestoneTitle">Milestone</string>
<string name="newIssueLabelsTitle">Labels</string>
<string name="spinnerMilestoneText">%1$s [%2$s]</string>
<string name="dialogAssignessText">%1$s - @%2$s</string>
<string name="spinnerMilestoneText" translatable="false">%1$s [%2$s]</string>
<string name="dialogAssignessText" translatable="false">%1$s - @%2$s</string>
<string name="issueTitleEmpty">Issue title is empty</string>
<string name="issueDescriptionEmpty">Issue description is empty</string>
<string name="issueCreated">New issue created successfully</string>
@ -259,16 +256,16 @@
<string name="settingshomeScreenSelectorDialogTitle">Select Home Screen</string>
<!-- settings -->
<string name="noMoreData">No more data available.</string>
<string name="noMoreData">No more data available</string>
<string name="createLabel">New Label</string>
<string name="menuTitleText">Repo Menu</string>
<string name="labelName">Label Name</string>
<string name="labelColor">Label Color</string>
<string name="labelEmptyError">Label name is empty.</string>
<string name="labelNameError">Label name is not valid.</string>
<string name="labelEmptyError">Label name is empty</string>
<string name="labelNameError">Label name is not valid</string>
<string name="labelCreated">Label created.</string>
<string name="labelGeneralError">Something went wrong, please try again.</string>
<string name="labelGeneralError">Something went wrong, please try again</string>
<string name="labelUpdated">Label updated.</string>
<string name="noDataLabelsTab">No labels found</string>
@ -287,7 +284,7 @@
<!-- credits - this part does not need translation -->
<string name="alertDialogTokenRevokedTitle">Authorization Error</string>
<string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR your are not allowed to see these contents. In case of revoked Token, please logout and login again.</string>
<string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR your are not allowed to see these contents. In case of revoked Token, please logout and login again</string>
<string name="alertDialogTokenRevokedCopyNegativeButton">Cancel</string>
<string name="alertDialogTokenRevokedCopyPositiveButton">Logout</string>
<string name="labelDeleteTitle">Delete\u0020</string>
@ -315,18 +312,18 @@
<string name="newTeamDesc">Description</string>
<string name="newTeamPermission">Permission</string>
<string name="newTeamAccessControls">Access Controls</string>
<string name="newTeamPermissionRead">Members can view and clone team repositories.</string>
<string name="newTeamPermissionWrite">Members can read and push to team repositories.</string>
<string name="newTeamPermissionAdmin">Members can pull and push to team repositories and add collaborators to them.</string>
<string name="newTeamPermissionRead">Members can view and clone team repositories</string>
<string name="newTeamPermissionWrite">Members can read and push to team repositories</string>
<string name="newTeamPermissionAdmin">Members can pull and push to team repositories and add collaborators to them</string>
<string name="newTeamPermissionValues" translatable="false">%1$s%2$s,\u0020</string>
<string name="newTeamPermissionValuesFinal" translatable="false">%1$s%2$s,\u0020</string>
<string name="teamNameEmpty">Please enter team name.</string>
<string name="teamNameError">Team name should contain only alphanumeric, dash (-), underscore (_) and dot (.) characters.</string>
<string name="teamPermissionEmpty">Please select permission.</string>
<string name="teamDescError">Team description have illegal characters.</string>
<string name="teamDescLimit">Team description have more than 100 characters.</string>
<string name="teamCreated">Team created successfully.</string>
<string name="teamCreatedError">Something went wrong, please try again.</string>
<string name="teamNameEmpty">Please enter team name</string>
<string name="teamNameError">Team name should contain only alphanumeric, dash (-), underscore (_) and dot (.) characters</string>
<string name="teamPermissionEmpty">Please select permission</string>
<string name="teamDescError">Team description have illegal characters</string>
<string name="teamDescLimit">Team description have more than 100 characters</string>
<string name="teamCreated">Team created successfully</string>
<string name="teamCreatedError">Something went wrong, please try again</string>
<!-- create team -->
<!-- edit comment -->
@ -353,8 +350,8 @@
<string name="profileEmailTitle">Email Address</string>
<string name="emailAddedText">New email added successfully.</string>
<string name="emailErrorEmpty">Email address is empty.</string>
<string name="emailErrorInvalid">Email address is not valid.</string>
<string name="emailErrorInUse">Email address is already in use.</string>
<string name="emailErrorInvalid">Email address is not valid</string>
<string name="emailErrorInUse">Email address is already in use</string>
<string name="emailTypeText">Primary</string>
<string name="profileTabEmails">Emails</string>
<string name="usernameWithAt" translatable="false">\u0040\u0020%1$s</string>
@ -470,6 +467,12 @@
<string name="milestoneCompletion">%1$d\uFF05 completed</string>
<!-- files -->
<string name="noDataFilesTab">No files found</string>
<string name="filesDirNotSupportedYet">Directory browsing is not supported yet</string>
<string name="filesGenericError">Sorry this file cannot be viewed as API returned an error</string>
<string name="filesBreadcrumb">Root</string>
<!-- generic copy -->
<string name="okButton">OK</string>
<string name="doneButton">Done</string>
@ -494,7 +497,6 @@
<string name="locationText">Location</string>
<string name="characters255Limit">Max 255 characters</string>
<string name="emptyFields">All fields are required</string>
<string name="translateText">Translate GitNex with Crowdin</string>
<!-- generic copy -->
</resources>

View File

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:3.5.1'
}
}

View File

@ -0,0 +1,6 @@
Bugfix: crash when repo avatar in not present in api nodes. old Gitea instances
Bugfix: Milestone progress bar fix
Bugfix: Create new issue enable/disable fix
For more, check the release notes.
https://gitea.com/mmarif/GitNex/releases

View File

@ -0,0 +1,4 @@
Bugfix: crash when my repo, starred repos are accessed without repo avatar. old Gitea instances
For more, check the release notes.
https://gitea.com/mmarif/GitNex/releases

View File

@ -0,0 +1,13 @@
2.1.3
Bugfix: another old Gitea instances API issue
2.1.0
- New: Font - Roboto
- New: Milestone progress bar @6543
- New: Redesign issues list
- New: Copy issue URL to clipboard @6543
- New: Redesign milestones list
- New: Added repository avatars
For more, check the release notes.
https://gitea.com/mmarif/GitNex/releases