diff --git a/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java index 7fcd430f..46a17b9a 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java @@ -23,6 +23,8 @@ import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.models.Branches; +import org.mian.gitnex.models.DeleteFile; +import org.mian.gitnex.models.EditFile; import org.mian.gitnex.models.NewFile; import java.util.ArrayList; import java.util.List; @@ -44,8 +46,12 @@ public class CreateFileActivity extends BaseActivity { private EditText newFileBranchName; private EditText newFileCommitMessage; private Spinner newFileBranchesSpinner; + private String filePath; + private String fileSha; + private int fileAction = 0; // 0 = create, 1 = delete, 2 = edit final Context ctx = this; private Context appCtx; + private TinyDB tinyDb; List branchesList = new ArrayList<>(); @@ -59,12 +65,12 @@ public class CreateFileActivity extends BaseActivity { super.onCreate(savedInstanceState); appCtx = getApplicationContext(); + tinyDb = new TinyDB(appCtx); boolean connToInternet = AppUtil.hasNetworkConnection(appCtx); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - TinyDB tinyDb = new TinyDB(appCtx); final String instanceUrl = tinyDb.getString("instanceUrl"); final String loginUid = tinyDb.getString("loginUid"); String repoFullName = tinyDb.getString("repoFullName"); @@ -80,6 +86,8 @@ public class CreateFileActivity extends BaseActivity { newFileCommitMessage = findViewById(R.id.newFileCommitMessage); TextView branchNameId = findViewById(R.id.branchNameId); TextView branchNameHintText = findViewById(R.id.branchNameHintText); + TextView toolbarTitle = findViewById(R.id.toolbarTitle); + TextView fileNameHint = findViewById(R.id.fileNameHint); newFileName.requestFocus(); assert imm != null; @@ -90,6 +98,46 @@ public class CreateFileActivity extends BaseActivity { newFileCreate = findViewById(R.id.newFileCreate); + if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", 1) == 1) { + + fileNameHint.setVisibility(View.GONE); + fileAction = getIntent().getIntExtra("fileAction", 1); + + filePath = getIntent().getStringExtra("filePath"); + String fileContents = getIntent().getStringExtra("fileContents"); + fileSha = getIntent().getStringExtra("fileSha"); + + toolbarTitle.setText(getString(R.string.deleteFileText, filePath)); + + newFileCreate.setText(R.string.deleteFile); + newFileName.setText(filePath); + newFileName.setEnabled(false); + newFileName.setFocusable(false); + + newFileContent.setText(fileContents); + newFileContent.setEnabled(false); + newFileContent.setFocusable(false); + } + + if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", 2) == 2) { + + fileNameHint.setVisibility(View.GONE); + fileAction = getIntent().getIntExtra("fileAction", 2); + + filePath = getIntent().getStringExtra("filePath"); + String fileContents = getIntent().getStringExtra("fileContents"); + fileSha = getIntent().getStringExtra("fileSha"); + + toolbarTitle.setText(getString(R.string.editFileText, filePath)); + + newFileCreate.setText(R.string.editFile); + newFileName.setText(filePath); + newFileName.setEnabled(false); + newFileName.setFocusable(false); + + newFileContent.setText(fileContents); + } + initCloseListener(); closeActivity.setOnClickListener(onClickListener); @@ -197,7 +245,22 @@ public class CreateFileActivity extends BaseActivity { else { disableProcessButton(); - createNewFile(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, newFileName_, appUtil.encodeBase64(newFileContent_), newFileBranchName_, newFileCommitMessage_, currentBranch.toString()); + + if(fileAction == 1) { + + deleteFile(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, filePath, + newFileBranchName_, newFileCommitMessage_, currentBranch.toString(), fileSha); + } + else if(fileAction == 2) { + + editFile(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, filePath, + appUtil.encodeBase64(newFileContent_), newFileBranchName_, newFileCommitMessage_, currentBranch.toString(), fileSha); + } + else { + + createNewFile(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, newFileName_, + appUtil.encodeBase64(newFileContent_), newFileBranchName_, newFileCommitMessage_, currentBranch.toString()); + } } @@ -256,6 +319,7 @@ public class CreateFileActivity extends BaseActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e("onFailure", t.toString()); enableProcessButton(); } @@ -263,6 +327,149 @@ public class CreateFileActivity extends BaseActivity { } + private void deleteFile(final String instanceUrl, final String token, String repoOwner, String repoName, String fileName, String fileBranchName, String fileCommitMessage, String currentBranch, String fileSha) { + + String branchName; + DeleteFile deleteFileJsonStr; + if(currentBranch.equals("No branch")) { + + branchName = fileBranchName; + deleteFileJsonStr = new DeleteFile("", fileCommitMessage, fileBranchName, fileSha); + } + else { + + branchName = currentBranch; + deleteFileJsonStr = new DeleteFile(currentBranch, fileCommitMessage, "", fileSha); + } + + Call call = RetrofitClient + .getInstance(instanceUrl, ctx) + .getApiInterface() + .deleteFile(token, repoOwner, repoName, fileName, deleteFileJsonStr); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if(response.code() == 200) { + + enableProcessButton(); + Toasty.info(ctx, getString(R.string.deleteFileMessage, branchName)); + getIntent().removeExtra("filePath"); + getIntent().removeExtra("fileSha"); + getIntent().removeExtra("fileContents"); + finish(); + + } + else if(response.code() == 401) { + + enableProcessButton(); + 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() == 404) { + + enableProcessButton(); + Toasty.info(ctx, getString(R.string.apiNotFound)); + } + else { + + enableProcessButton(); + Toasty.info(ctx, getString(R.string.genericError)); + } + + } + + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + Log.e("onFailure", t.toString()); + enableProcessButton(); + } + }); + + } + + private void editFile(final String instanceUrl, final String token, String repoOwner, String repoName, String fileName, String fileContent, String fileBranchName, String fileCommitMessage, String currentBranch, String fileSha) { + + String branchName; + EditFile editFileJsonStr; + if(currentBranch.equals("No branch")) { + + branchName = fileBranchName; + editFileJsonStr = new EditFile("", fileCommitMessage, fileBranchName, fileSha, fileContent); + } + else { + + branchName = currentBranch; + editFileJsonStr = new EditFile(currentBranch, fileCommitMessage, "", fileSha, fileContent); + } + + Call call = RetrofitClient + .getInstance(instanceUrl, ctx) + .getApiInterface() + .editFile(token, repoOwner, repoName, fileName, editFileJsonStr); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if(response.code() == 200) { + + enableProcessButton(); + Toasty.info(ctx, getString(R.string.editFileMessage, branchName)); + getIntent().removeExtra("filePath"); + getIntent().removeExtra("fileSha"); + getIntent().removeExtra("fileContents"); + tinyDb.putBoolean("fileModified", true); + finish(); + + } + else if(response.code() == 401) { + + enableProcessButton(); + 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() == 404) { + + enableProcessButton(); + Toasty.info(ctx, getString(R.string.apiNotFound)); + } + else { + + enableProcessButton(); + Toasty.info(ctx, getString(R.string.genericError)); + } + + } + + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + Log.e("onFailure", t.toString()); + enableProcessButton(); + } + }); + + } + private void getBranches(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) { Call> call = RetrofitClient diff --git a/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java b/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java index 93ef61b7..4586a4ac 100644 --- a/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java @@ -84,6 +84,7 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie private byte[] decodedPdf; private Boolean pdfNightMode; private String singleFileName; + private String fileSha; private AppUtil appUtil; private TinyDB tinyDb; @@ -153,6 +154,27 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie } + @Override + public void onResume() { + + super.onResume(); + + String repoFullName = tinyDb.getString("repoFullName"); + String repoBranch = tinyDb.getString("repoBranch"); + String[] parts = repoFullName.split("/"); + String repoOwner = parts[0]; + String repoName = parts[1]; + String instanceUrl = tinyDb.getString("instanceUrl"); + String loginUid = tinyDb.getString("loginUid"); + String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); + + if(tinyDb.getBoolean("fileModified")) { + getSingleFileContents(instanceUrl, instanceToken, repoOwner, repoName, singleFileName, repoBranch); + tinyDb.putBoolean("fileModified", false); + } + } + + private void getSingleFileContents(String instanceUrl, String token, final String owner, String repo, final String filename, String ref) { Call call = RetrofitClient.getInstance(instanceUrl, ctx).getApiInterface().getSingleFileContents(token, owner, repo, filename, ref); @@ -171,6 +193,8 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie String fileExtension = FileUtils.getExtension(filename); mProgressBar.setVisibility(View.GONE); + fileSha = response.body().getSha(); + // download file meta tinyDb.putString("downloadFileName", filename); tinyDb.putString("downloadFileContents", response.body().getContent()); @@ -403,7 +427,42 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie if("downloadFile".equals(text)) { requestFileDownload(); + } + if("deleteFile".equals(text)) { + + String fileExtension = FileUtils.getExtension(singleFileName); + String data = appUtil.decodeBase64(tinyDb.getString("downloadFileContents")); + Intent intent = new Intent(ctx, CreateFileActivity.class); + intent.putExtra("fileAction", 1); + intent.putExtra("filePath", singleFileName); + intent.putExtra("fileSha", fileSha); + if(!appUtil.imageExtension(fileExtension)) { + intent.putExtra("fileContents", data); + } + else { + intent.putExtra("fileContents", ""); + } + + ctx.startActivity(intent); + } + + if("editFile".equals(text)) { + + String fileExtension = FileUtils.getExtension(singleFileName); + String data = appUtil.decodeBase64(tinyDb.getString("downloadFileContents")); + Intent intent = new Intent(ctx, CreateFileActivity.class); + intent.putExtra("fileAction", 2); + intent.putExtra("filePath", singleFileName); + intent.putExtra("fileSha", fileSha); + if(!appUtil.imageExtension(fileExtension)) { + intent.putExtra("fileContents", data); + } + else { + intent.putExtra("fileContents", ""); + } + + ctx.startActivity(intent); } } @@ -426,6 +485,7 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie } else { + Toasty.warning(ctx, getString(R.string.waitLoadingDownloadFile)); } @@ -456,6 +516,7 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie } catch(IOException e) { + Log.e("errorFileDownloading", Objects.requireNonNull(e.getMessage())); } @@ -469,7 +530,6 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie getIntent().removeExtra("singleFileName"); finish(); - }; } diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java index b913c5cc..b19f6e69 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java @@ -26,15 +26,27 @@ public class BottomSheetFileViewerFragment extends BottomSheetDialogFragment { View v = inflater.inflate(R.layout.bottom_sheet_file_viewer, container, false); TextView downloadFile = v.findViewById(R.id.downloadFile); + TextView deleteFile = v.findViewById(R.id.deleteFile); + TextView editFile = v.findViewById(R.id.editFile); - downloadFile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - bmListener.onButtonClicked("downloadFile"); - dismiss(); - } + downloadFile.setOnClickListener(v1 -> { + + bmListener.onButtonClicked("downloadFile"); + dismiss(); }); + deleteFile.setOnClickListener(v1 -> { + + bmListener.onButtonClicked("deleteFile"); + dismiss(); + }); + + editFile.setOnClickListener(v1 -> { + + bmListener.onButtonClicked("editFile"); + dismiss(); + }); + return v; } @@ -47,9 +59,11 @@ public class BottomSheetFileViewerFragment extends BottomSheetDialogFragment { super.onAttach(context); try { + bmListener = (BottomSheetFileViewerFragment.BottomSheetListener) context; } catch (ClassCastException e) { + throw new ClassCastException(context.toString() + " must implement BottomSheetListener"); } } 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 74f6adf3..843614cf 100644 --- a/app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java +++ b/app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java @@ -7,6 +7,8 @@ import org.mian.gitnex.models.Collaborators; import org.mian.gitnex.models.Commits; import org.mian.gitnex.models.CreateIssue; import org.mian.gitnex.models.CreateLabel; +import org.mian.gitnex.models.DeleteFile; +import org.mian.gitnex.models.EditFile; import org.mian.gitnex.models.Emails; import org.mian.gitnex.models.ExploreRepositories; import org.mian.gitnex.models.Files; @@ -39,6 +41,7 @@ import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.DELETE; import retrofit2.http.GET; +import retrofit2.http.HTTP; import retrofit2.http.Header; import retrofit2.http.PATCH; import retrofit2.http.POST; @@ -265,6 +268,12 @@ public interface ApiInterface { @GET("repos/{owner}/{repo}/contents/{fileDir}") // get all the sub files and dirs of a repository Call> getDirFiles(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("fileDir") String fileDir, @Query("ref") String ref); + @HTTP(method = "DELETE", path = "repos/{owner}/{repo}/contents/{filepath}", hasBody = true) // delete a file + Call deleteFile(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("filepath") String filepath, @Body DeleteFile jsonStr); + + @PUT("repos/{owner}/{repo}/contents/{filepath}") // edit/update a file + Call editFile(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("filepath") String filepath, @Body EditFile jsonStr); + @GET("user/starred/{owner}/{repo}") // check star status of a repository Call checkRepoStarStatus(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName); diff --git a/app/src/main/java/org/mian/gitnex/models/DeleteFile.java b/app/src/main/java/org/mian/gitnex/models/DeleteFile.java new file mode 100644 index 00000000..35d19ae2 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/models/DeleteFile.java @@ -0,0 +1,60 @@ +package org.mian.gitnex.models; + +/** + * Author M M Arif + */ + +public class DeleteFile { + + private String branch; + private String message; + private String new_branch; + private String sha; + + public String getBranch() { + + return branch; + } + + public void setBranch(String branch) { + + this.branch = branch; + } + + public String getMessage() { + + return message; + } + + public void setMessage(String message) { + + this.message = message; + } + + public String getNew_branch() { + + return new_branch; + } + + public void setNew_branch(String new_branch) { + + this.new_branch = new_branch; + } + + public String getSha() { + + return sha; + } + + public void setSha(String sha) { + + this.sha = sha; + } + + public DeleteFile(String branch, String message, String new_branch, String sha) { + this.branch = branch; + this.message = message; + this.new_branch = new_branch; + this.sha = sha; + } +} diff --git a/app/src/main/java/org/mian/gitnex/models/EditFile.java b/app/src/main/java/org/mian/gitnex/models/EditFile.java new file mode 100644 index 00000000..4461ada0 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/models/EditFile.java @@ -0,0 +1,73 @@ +package org.mian.gitnex.models; + +/** + * Author M M Arif + */ + +public class EditFile { + + private String branch; + private String message; + private String new_branch; + private String sha; + private String content; + + public String getBranch() { + + return branch; + } + + public void setBranch(String branch) { + + this.branch = branch; + } + + public String getMessage() { + + return message; + } + + public void setMessage(String message) { + + this.message = message; + } + + public String getNew_branch() { + + return new_branch; + } + + public void setNew_branch(String new_branch) { + + this.new_branch = new_branch; + } + + public String getSha() { + + return sha; + } + + public void setSha(String sha) { + + this.sha = sha; + } + + public String getContent() { + + return content; + } + + public void setContent(String content) { + + this.content = content; + } + + public EditFile(String branch, String message, String new_branch, String sha, String content) { + this.branch = branch; + this.message = message; + this.new_branch = new_branch; + this.sha = sha; + this.content = content; + } + +} diff --git a/app/src/main/java/org/mian/gitnex/models/NewFile.java b/app/src/main/java/org/mian/gitnex/models/NewFile.java index 64012eab..3d13067c 100644 --- a/app/src/main/java/org/mian/gitnex/models/NewFile.java +++ b/app/src/main/java/org/mian/gitnex/models/NewFile.java @@ -46,7 +46,7 @@ public class NewFile { this.new_branch = new_branch; } - public class authorObject { + public static class authorObject { private String email; private String name; @@ -68,7 +68,7 @@ public class NewFile { } } - public class committerObject { + public static class committerObject { private String email; private String name; @@ -96,4 +96,4 @@ public class NewFile { this.message = message; this.new_branch = new_branch; } -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/activity_new_file.xml b/app/src/main/res/layout/activity_new_file.xml index e2efd6e9..91f169d8 100644 --- a/app/src/main/res/layout/activity_new_file.xml +++ b/app/src/main/res/layout/activity_new_file.xml @@ -30,7 +30,7 @@ android:src="@drawable/ic_close" /> + + + + Please wait for the file to load to memory File saved successfully This file type is not supported in file viewer. Download it instead from the three dotted menu? + Delete This File + Edit This File + Delete %1$s + File is set for deletion by branch %1$s + Edit %1$s + File is modified by branch %1$s Size Share Issue