Implement drafts, introduce Room persistence library for db #139

Open
mmarif wants to merge 25 commits from 15-comments-draft into master
34 changed files with 2330 additions and 347 deletions

@ -76,6 +76,8 @@ dependencies {
implementation "com.hendraanggrian.appcompat:socialview-commons:0.2"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "android.arch.persistence.room:runtime:1.1.1"
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
implementation "com.github.HamidrezaAmz:BreadcrumbsView:0.2.9"
implementation "commons-io:commons-io:20030203.000550"
implementation "com.github.chrisbanes:PhotoView:2.3.0"
@ -84,5 +86,7 @@ dependencies {
implementation "ch.acra:acra-mail:$acra"
implementation "ch.acra:acra-limiter:$acra"
implementation "ch.acra:acra-notification:$acra"
implementation "androidx.room:room-runtime:2.2.5"
annotationProcessor "androidx.room:room-compiler:2.2.5"
}

@ -20,9 +20,11 @@ import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.LifecycleOwner;
import com.tooltip.Tooltip;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.repository.UserAccountsRepository;
import org.mian.gitnex.helpers.NetworkObserver;
import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.VersionCheck;
@ -31,6 +33,7 @@ import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.models.UserTokens;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.UserAccountsDatabaseViewModel;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
@ -547,6 +550,18 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
tinyDb.putString("loginUid", userDetails.getLogin());
tinyDb.putString("userLogin", userDetails.getUsername());
// insert new account to db if does not exist
String accountName = userDetails.getUsername() + "@" + instanceUrl;
UserAccountsRepository userAccountsRepository = new UserAccountsRepository(ctx);
UserAccountsDatabaseViewModel.getCount(accountName).observe((LifecycleOwner) ctx, count -> {
if(count == 0) {
userAccountsRepository.insertNewAccount(accountName, instanceUrl, userDetails.getUsername(), loginToken_,"");
}
});
enableProcessButton();
loginButton.setText(R.string.btnLogin);
startActivity(new Intent(LoginActivity.this, MainActivity.class));
@ -711,6 +726,18 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
tinyDb.putString(loginUid + "-token", newToken.getSha1());
tinyDb.putString(loginUid + "-token-last-eight", appUtil.getLastCharactersOfWord(newToken.getSha1(), 8));
// insert new account to db if does not exist
String accountName = userDetails.getUsername() + "@" + instanceUrl;
UserAccountsRepository userAccountsRepository = new UserAccountsRepository(ctx);
UserAccountsDatabaseViewModel.getCount(accountName).observe((LifecycleOwner) ctx, count -> {
if(count == 0) {
userAccountsRepository.insertNewAccount(accountName, instanceUrl, userDetails.getUsername(), newToken.getSha1(),"");
}
});
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
@ -771,7 +798,8 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
}
else {
String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String token = tinyDb.getString(loginUid + "-token");
String instanceToken = "token " + token;
Call<UserInfo> callGetUsername = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
@ -793,6 +821,19 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
tinyDb.putString("userLogin", userDetails.getUsername());
tinyDb.putBoolean("loggedInMode", true);
// insert new account to db if does not exist
String accountName = userDetails.getUsername() + "@" + instanceUrl;
UserAccountsRepository userAccountsRepository = new UserAccountsRepository(ctx);
UserAccountsDatabaseViewModel.getCount(accountName).observe((LifecycleOwner) ctx, count -> {
if(count == 0) {
userAccountsRepository.insertNewAccount(accountName, instanceUrl, userDetails.getUsername(), token,"");
}
});
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();

@ -16,6 +16,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
@ -26,7 +27,11 @@ import com.squareup.picasso.NetworkPolicy;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.models.UserAccounts;
import org.mian.gitnex.database.repository.UserAccountsRepository;
import org.mian.gitnex.fragments.AboutFragment;
import org.mian.gitnex.fragments.BottomSheetDraftsFragment;
import org.mian.gitnex.fragments.DraftsFragment;
import org.mian.gitnex.fragments.AdministrationFragment;
import org.mian.gitnex.fragments.ExploreRepositoriesFragment;
import org.mian.gitnex.fragments.MyRepositoriesFragment;
@ -45,6 +50,7 @@ import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import retrofit2.Call;
import retrofit2.Callback;
@ -52,372 +58,472 @@ import retrofit2.Callback;
* Author M M Arif
*/
public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener {
public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, BottomSheetDraftsFragment.BottomSheetListener {
private DrawerLayout drawer;
private TextView userFullName;
private TextView userEmail;
private ImageView userAvatar;
private TextView toolbarTitle;
final Context ctx = this;
private Typeface myTypeface;
private DrawerLayout drawer;
private TextView userFullName;
private TextView userEmail;
private ImageView userAvatar;
private TextView toolbarTitle;
final Context ctx = this;
private Typeface myTypeface;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_main;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putBoolean("noConnection", false);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(tinyDb.getString("dateFormat").isEmpty()) {
tinyDb.putString("dateFormat", "pretty");
}
if(tinyDb.getString("codeBlockStr").isEmpty()) {
tinyDb.putInt("codeBlockColor", getResources().getColor(R.color.colorLightGreen));
tinyDb.putInt("codeBlockBackground", getResources().getColor(R.color.black));
}
if(tinyDb.getString("enableCounterIssueBadgeInit").isEmpty()) {
tinyDb.putBoolean("enableCounterIssueBadge", true);
}
if(tinyDb.getString("homeScreenStr").isEmpty()) {
tinyDb.putInt("homeScreenId", 0);
}
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
if(!tinyDb.getBoolean("loggedInMode")) {
logout(this, ctx);
return;
}
String accountName = loginUid + "@" + instanceUrl;
try {
getAcountData(accountName);
}
catch(ExecutionException | InterruptedException e) {
Log.e("getAcountData", e.toString());
}
Toolbar toolbar = findViewById(R.id.toolbar);
toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
setSupportActionBar(toolbar);
FragmentManager fm = getSupportFragmentManager();
Fragment fragmentById = fm.findFragmentById(R.id.fragment_container);
if (fragmentById instanceof SettingsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleSettings));
}
else if (fragmentById instanceof MyRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
}
else if (fragmentById instanceof StarredRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
}
else if (fragmentById instanceof OrganizationsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
}
else if (fragmentById instanceof ExploreRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
}
else if (fragmentById instanceof ProfileFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
}
else if (fragmentById instanceof AboutFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleAbout));
}
else if (fragmentById instanceof DraftsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleDrafts));
}
else if (fragmentById instanceof AdministrationFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
}
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
final View hView = navigationView.getHeaderView(0);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
toggle.getDrawerArrowDrawable().setColor(getResources().getColor(R.color.darkGreen));
drawer.addDrawerListener(toggle);
drawer.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
}
@Override
public void onDrawerOpened(@NonNull View drawerView) {
if(tinyDb.getBoolean("noConnection")) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
tinyDb.putBoolean("noConnection", false);
}
String userEmailNav = tinyDb.getString("userEmail");
String userFullNameNav = tinyDb.getString("userFullname");
String userAvatarNav = tinyDb.getString("userAvatar");
userEmail = hView.findViewById(R.id.userEmail);
if (!userEmailNav.equals("")) {
userEmail.setText(userEmailNav);
userEmail.setTypeface(myTypeface);
}
userFullName = hView.findViewById(R.id.userFullname);
if (!userFullNameNav.equals("")) {
userFullName.setText(userFullNameNav);
userFullName.setTypeface(myTypeface);
}
userAvatar = hView.findViewById(R.id.userAvatar);
if (!userAvatarNav.equals("")) {
PicassoService.getInstance(ctx).get().load(userAvatarNav).networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar);
}
userAvatar.setOnClickListener(v -> {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ProfileFragment()).commit();
drawer.closeDrawers();
});
}
@Override
public void onDrawerClosed(@NonNull View drawerView) {
// Called when a drawer has settled in a completely closed state.
}
@Override
public void onDrawerStateChanged(int newState) {
// Called when the drawer motion state changes. The new state will be one of STATE_IDLE, STATE_DRAGGING or STATE_SETTLING.
}
});
toggle.syncState();
if(savedInstanceState == null) {
if(tinyDb.getInt("homeScreenId") == 0) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
else if(tinyDb.getInt("homeScreenId") == 1) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StarredRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_starred_repos);
}
else if(tinyDb.getInt("homeScreenId") == 2) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new OrganizationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_organizations);
}
else if(tinyDb.getInt("homeScreenId") == 3) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new RepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_repositories);
}
else if(tinyDb.getInt("homeScreenId") == 4) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ProfileFragment()).commit();
navigationView.setCheckedItem(R.id.nav_profile);
}
else {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
}
if(!connToInternet) {
if(!tinyDb.getBoolean("noConnection")) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
}
tinyDb.putBoolean("noConnection", true);
} else {
displayUserInfo(instanceUrl, instanceToken, loginUid);
giteaVersion(instanceUrl);
tinyDb.putBoolean("noConnection", false);
}
// Changelog popup
int versionCode = 0;
try {
PackageInfo packageInfo = getApplicationContext().getPackageManager()
.getPackageInfo(getApplicationContext().getPackageName(), 0);
versionCode = packageInfo.versionCode;
}
catch (PackageManager.NameNotFoundException e) {
Log.e("changelogDialog", Objects.requireNonNull(e.getMessage()));
}
if (versionCode > tinyDb.getInt("versionCode")) {
tinyDb.putInt("versionCode", versionCode);
tinyDb.putBoolean("versionFlag", true);
ChangeLog changelogDialog = new ChangeLog(this);
changelogDialog.showDialog();
}
}
@Override
protected int getLayoutResourceId() {
public void onButtonClicked(String text) {
return R.layout.activity_main;
}
TinyDB tinyDb = new TinyDB(ctx);
int currentActiveAccountId = tinyDb.getInt("currentActiveAccountId");
@Override
public void onCreate(Bundle savedInstanceState) {
if("deleteDrafts".equals(text)) {
super.onCreate(savedInstanceState);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putBoolean("noConnection", false);
//userAvatar = findViewById(R.id.userAvatar);
if(currentActiveAccountId > 0) {
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
FragmentManager fm = getSupportFragmentManager();
DraftsFragment frag = (DraftsFragment) fm.findFragmentById(R.id.fragment_container);
if(tinyDb.getString("dateFormat").isEmpty()) {
tinyDb.putString("dateFormat", "pretty");
}
if(frag != null) {
if(tinyDb.getString("codeBlockStr").isEmpty()) {
tinyDb.putInt("codeBlockColor", getResources().getColor(R.color.colorLightGreen));
tinyDb.putInt("codeBlockBackground", getResources().getColor(R.color.black));
}
new AlertDialog.Builder(ctx)
.setTitle(R.string.deleteAllDrafts)
.setIcon(R.drawable.ic_delete)
.setCancelable(false)
.setMessage(R.string.deleteAllDraftsDialogMessage)
.setPositiveButton(R.string.menuDeleteText, (dialog, which) -> {
if(tinyDb.getString("enableCounterIssueBadgeInit").isEmpty()) {
tinyDb.putBoolean("enableCounterIssueBadge", true);
}
frag.deleteAllDrafts(currentActiveAccountId);
dialog.dismiss();
if(tinyDb.getString("homeScreenStr").isEmpty()) {
tinyDb.putInt("homeScreenId", 0);
}
})
.setNegativeButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss())
.show();
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
if(!tinyDb.getBoolean("loggedInMode")) {
logout(this, ctx);
return;
}
Toolbar toolbar = findViewById(R.id.toolbar);
toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
setSupportActionBar(toolbar);
FragmentManager fm = getSupportFragmentManager();
Fragment fragmentById = fm.findFragmentById(R.id.fragment_container);
if(fragmentById instanceof SettingsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleSettings));
}
else if(fragmentById instanceof MyRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
}
else if(fragmentById instanceof StarredRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
}
else if(fragmentById instanceof OrganizationsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
}
else if(fragmentById instanceof ExploreRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
}
else if(fragmentById instanceof ProfileFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
}
else if(fragmentById instanceof AboutFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleAbout));
}
else if(fragmentById instanceof AdministrationFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
}
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
final View hView = navigationView.getHeaderView(0);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
toggle.getDrawerArrowDrawable().setColor(getResources().getColor(R.color.darkGreen));
drawer.addDrawerListener(toggle);
drawer.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
}
@Override
public void onDrawerOpened(@NonNull View drawerView) {
if(tinyDb.getBoolean("noConnection")) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
tinyDb.putBoolean("noConnection", false);
}
else {
Toasty.error(ctx, getResources().getString(R.string.genericError));
}
String userEmailNav = tinyDb.getString("userEmail");
String userFullNameNav = tinyDb.getString("userFullname");
String userAvatarNav = tinyDb.getString("userAvatar");
userEmail = hView.findViewById(R.id.userEmail);
if(!userEmailNav.equals("")) {
userEmail.setText(userEmailNav);
userEmail.setTypeface(myTypeface);
}
userFullName = hView.findViewById(R.id.userFullname);
if(!userFullNameNav.equals("")) {
userFullName.setText(userFullNameNav);
userFullName.setTypeface(myTypeface);
}
userAvatar = hView.findViewById(R.id.userAvatar);
if(!userAvatarNav.equals("")) {
PicassoService.getInstance(ctx).get().load(userAvatarNav).networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar);
}
userAvatar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
drawer.closeDrawers();
}
});
}
@Override
public void onDrawerClosed(@NonNull View drawerView) {
// Called when a drawer has settled in a completely closed state.
}
@Override
public void onDrawerStateChanged(int newState) {
// Called when the drawer motion state changes. The new state will be one of STATE_IDLE, STATE_DRAGGING or STATE_SETTLING.
}
});
toggle.syncState();
if(savedInstanceState == null) {
if(tinyDb.getInt("homeScreenId") == 0) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
else if(tinyDb.getInt("homeScreenId") == 1) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new StarredRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_starred_repos);
}
else if(tinyDb.getInt("homeScreenId") == 2) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OrganizationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_organizations);
}
else if(tinyDb.getInt("homeScreenId") == 3) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new RepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_repositories);
}
else if(tinyDb.getInt("homeScreenId") == 4) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
navigationView.setCheckedItem(R.id.nav_profile);
}
else {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
}
if(!connToInternet) {
if(!tinyDb.getBoolean("noConnection")) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.genericError));
}
tinyDb.putBoolean("noConnection", true);
}
else {
displayUserInfo(instanceUrl, instanceToken, loginUid);
giteaVersion(instanceUrl);
tinyDb.putBoolean("noConnection", false);
}
// Changelog popup
int versionCode = 0;
try {
PackageInfo packageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
versionCode = packageInfo.versionCode;
}
catch(PackageManager.NameNotFoundException e) {
Log.e("changelogDialog", Objects.requireNonNull(e.getMessage()));
}
if(versionCode > tinyDb.getInt("versionCode")) {
tinyDb.putInt("versionCode", versionCode);
tinyDb.putBoolean("versionFlag", true);
ChangeLog changelogDialog = new ChangeLog(this);
changelogDialog.showDialog();
}
}
public void setActionBarTitle(@NonNull String title) {
public void getAcountData(String accountName) throws ExecutionException, InterruptedException {
Objects.requireNonNull(getSupportActionBar()).setTitle(title);
}
UserAccountsRepository accountData = new UserAccountsRepository(ctx);
UserAccounts data = accountData.getAccountData(accountName);
if(data != null) {
TinyDB tinyDb = new TinyDB(ctx.getApplicationContext());
tinyDb.putInt("currentActiveAccountId", data.getAccountId());
}
else {
AlertDialogs.forceLogoutDialog(ctx, getResources().getString(R.string.forceLogoutDialogHeader), getResources().getString(R.string.forceLogoutDialogDescription), getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
}
@Override
public void onBackPressed() {
public void onBackPressed() {
if(drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else {
super.onBackPressed();
}
if(drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else {
super.onBackPressed();
}
}
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_home:
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MyRepositoriesFragment()).commit();
break;
case R.id.nav_organizations:
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new OrganizationsFragment()).commit();
break;
case R.id.nav_profile:
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ProfileFragment()).commit();
break;
case R.id.nav_repositories:
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new RepositoriesFragment()).commit();
break;
case R.id.nav_settings:
toolbarTitle.setText(getResources().getString(R.string.pageTitleSettings));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new SettingsFragment()).commit();
break;
case R.id.nav_logout:
logout(this, ctx);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
break;
case R.id.nav_about:
toolbarTitle.setText(getResources().getString(R.string.pageTitleAbout));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new AboutFragment()).commit();
break;
case R.id.nav_rate_app:
rateThisApp();
break;
case R.id.nav_starred_repos:
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StarredRepositoriesFragment()).commit();
break;
case R.id.nav_explore:
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ExploreRepositoriesFragment()).commit();
break;
case R.id.nav_comments_draft:
toolbarTitle.setText(getResources().getString(R.string.pageTitleDrafts));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new DraftsFragment()).commit();
break;
case R.id.nav_administration:
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new AdministrationFragment()).commit();
break;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
public void rateThisApp() {
try {
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("market://details?id=" + getPackageName())));
} catch (ActivityNotFoundException e) {
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName())));
}
}
public static void logout(Activity activity, Context ctx) {
TinyDB tinyDb = new TinyDB(ctx.getApplicationContext());
tinyDb.putBoolean("loggedInMode", false);
tinyDb.remove("basicAuthPassword");
tinyDb.putBoolean("basicAuthFlag", false);
//tinyDb.clear();
activity.finish();
ctx.startActivity(new Intent(ctx, LoginActivity.class));
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
public boolean onOptionsItemSelected(MenuItem item) {
switch(menuItem.getItemId()) {
case R.id.nav_home:
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyRepositoriesFragment()).commit();
break;
case R.id.nav_organizations:
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OrganizationsFragment()).commit();
break;
case R.id.nav_profile:
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
break;
case R.id.nav_repositories:
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new RepositoriesFragment()).commit();
break;
case R.id.nav_settings:
toolbarTitle.setText(getResources().getString(R.string.pageTitleSettings));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SettingsFragment()).commit();
break;
case R.id.nav_logout:
logout(this, ctx);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
break;
case R.id.nav_about:
toolbarTitle.setText(getResources().getString(R.string.pageTitleAbout));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).commit();
break;
case R.id.nav_rate_app:
rateThisApp();
break;
case R.id.nav_starred_repos:
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new StarredRepositoriesFragment()).commit();
break;
case R.id.nav_explore:
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ExploreRepositoriesFragment()).commit();
break;
case R.id.nav_administration:
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AdministrationFragment()).commit();
break;
int id = item.getItemId();
if(id == R.id.genericMenu) {
BottomSheetDraftsFragment bottomSheet = new BottomSheetDraftsFragment();
bottomSheet.show(getSupportFragmentManager(), "draftsBottomSheet");
return true;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
public void rateThisApp() {
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName())));
}
catch(ActivityNotFoundException e) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName())));
}
}
public static void logout(Activity activity, Context ctx) {
TinyDB tinyDb = new TinyDB(ctx.getApplicationContext());
tinyDb.putBoolean("loggedInMode", false);
tinyDb.remove("basicAuthPassword");
tinyDb.putBoolean("basicAuthFlag", false);
//tinyDb.clear();
activity.finish();
ctx.startActivity(new Intent(ctx, LoginActivity.class));
return super.onOptionsItemSelected(item);
}
private void giteaVersion(final String instanceUrl) {
private void giteaVersion(final String instanceUrl) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
final TinyDB tinyDb = new TinyDB(getApplicationContext());
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
Call<GiteaVersion> callVersion = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().getGiteaVersionWithToken(token);
Call<GiteaVersion> callVersion = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getGiteaVersionWithToken(token);
callVersion.enqueue(new Callback<GiteaVersion>() {
callVersion.enqueue(new Callback<GiteaVersion>() {
@Override
public void onResponse(@NonNull final Call<GiteaVersion> callVersion, @NonNull retrofit2.Response<GiteaVersion> responseVersion) {
@Override
public void onResponse(@NonNull final Call<GiteaVersion> callVersion, @NonNull retrofit2.Response<GiteaVersion> responseVersion) {
if(responseVersion.code() == 200) {
if (responseVersion.code() == 200) {
GiteaVersion version = responseVersion.body();
assert version != null;
GiteaVersion version = responseVersion.body();
assert version != null;
tinyDb.putString("giteaVersion", version.getVersion());
tinyDb.putString("giteaVersion", version.getVersion());
}
}
}
}
@Override
public void onFailure(@NonNull Call<GiteaVersion> callVersion, @NonNull Throwable t) {
@Override
public void onFailure(@NonNull Call<GiteaVersion> callVersion, @NonNull Throwable t) {
Log.e("onFailure-version", t.toString());
Log.e("onFailure-version", t.toString());
}
}
});
});
}
}
private void displayUserInfo(String instanceUrl, String token, String loginUid) {
@ -489,13 +595,11 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
userEmail.setText("...");
}
userAvatar.setOnClickListener(new View.OnClickListener() {
userAvatar.setOnClickListener(v -> {
public void onClick(View v) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
drawer.closeDrawers();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
drawer.closeDrawers();
}
});
}
@ -508,7 +612,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
}
else {
String toastError = getResources().getString(R.string.genericApiStatusError) + String.valueOf(response.code());
String toastError = getResources().getString(R.string.genericApiStatusError) + response.code();
Toasty.info(getApplicationContext(), toastError);
}

@ -7,6 +7,8 @@ import retrofit2.Response;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
@ -20,14 +22,17 @@ import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.IssueActions;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.repository.DraftsRepository;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* Author M M Arif
@ -43,6 +48,7 @@ public class ReplyToIssueActivity extends BaseActivity {
private SocialAutoCompleteTextView addComment;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button replyButton;
private String TAG = StaticGlobalVariables.replyToIssueActivity;
@Override
protected int getLayoutResourceId(){
@ -83,26 +89,68 @@ public class ReplyToIssueActivity extends BaseActivity {
replyButton = findViewById(R.id.replyButton);
if(getIntent().getStringExtra("commentAction") != null && getIntent().getStringExtra("commentAction").equals("edit")) {
if(getIntent().getStringExtra("commentBody") != null) {
addComment.setText(getIntent().getStringExtra("commentBody"));
}
if(getIntent().getStringExtra("draftTitle") != null) {
toolbar_title.setText(getIntent().getStringExtra("draftTitle"));
}
if(getIntent().getStringExtra("commentAction") != null && getIntent().getStringExtra("commentAction").equals("edit")) {
final String commentId = getIntent().getStringExtra("commentId");
toolbar_title.setText(getResources().getString(R.string.editCommentTitle));
replyButton.setText(getResources().getString(R.string.editCommentButtonText));
replyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
disableProcessButton();
IssueActions.editIssueComment(ctx, Integer.valueOf(commentId), addComment.getText().toString());
addComment.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
saveDraft(addComment.getText().toString());
}
});
replyButton.setOnClickListener(v -> {
disableProcessButton();
IssueActions.editIssueComment(ctx, Integer.parseInt(commentId), addComment.getText().toString());
});
return;
}
addComment.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
saveDraft(addComment.getText().toString());
}
});
if(!connToInternet) {
disableProcessButton();
@ -115,6 +163,34 @@ public class ReplyToIssueActivity extends BaseActivity {
}
private void saveDraft(String draftText) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
int repositoryId = (int) tinyDb.getLong("repositoryId", 0);
int currentActiveAccountId = tinyDb.getInt("currentActiveAccountId");
int issueNumber = Integer.parseInt(tinyDb.getString("issueNumber"));
DraftsRepository draftsRepository = new DraftsRepository(getApplicationContext());
try {
int countDraft = draftsRepository.checkDraft(issueNumber, repositoryId);
if(countDraft == 0) {
long draftId = draftsRepository.insertDraft(repositoryId, currentActiveAccountId, issueNumber, draftText, StaticGlobalVariables.draftTypeComment);
}
else {
DraftsRepository.updateDraftByIssueIdAsycTask(draftText, issueNumber, repositoryId);
}
}
catch(ExecutionException | InterruptedException e) {
Log.e(TAG, e.toString());
}
}
public void loadCollaboratorsList() {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
@ -151,7 +227,7 @@ public class ReplyToIssueActivity extends BaseActivity {
} else {
Log.i("onResponse", String.valueOf(response.code()));
Log.i(TAG, String.valueOf(response.code()));
}
@ -159,7 +235,7 @@ public class ReplyToIssueActivity extends BaseActivity {
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage());
Log.e(TAG, t.toString());
}
});
@ -182,6 +258,8 @@ public class ReplyToIssueActivity extends BaseActivity {
private void processNewCommentReply() {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
String newReplyDT = addComment.getText().toString();
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
@ -260,7 +338,7 @@ public class ReplyToIssueActivity extends BaseActivity {
@Override
public void onFailure(@NonNull Call<Issues> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
Log.e(TAG, t.toString());
enableProcessButton();
}
});

@ -0,0 +1,127 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
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.ReplyToIssueActivity;
import org.mian.gitnex.database.models.DraftsWithRepositories;
import org.mian.gitnex.database.repository.DraftsRepository;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
/**
* Author M M Arif
*/
public class DraftsAdapter extends RecyclerView.Adapter<DraftsAdapter.DraftsViewHolder> {
private List<DraftsWithRepositories> draftsList;
private Context mCtx;
class DraftsViewHolder extends RecyclerView.ViewHolder {
private TextView draftText;
private TextView repoInfo;
private TextView repoId;
private TextView draftId;
private TextView issueNumber;
private TextView issueType;
private TextView repoOwner;
private TextView repoName;
private DraftsViewHolder(View itemView) {
super(itemView);
draftText = itemView.findViewById(R.id.draftText);
repoInfo = itemView.findViewById(R.id.repoInfo);
repoId = itemView.findViewById(R.id.repoId);
draftId = itemView.findViewById(R.id.draftId);
issueNumber = itemView.findViewById(R.id.issueNumber);
issueType = itemView.findViewById(R.id.issueType);
repoOwner = itemView.findViewById(R.id.repoOwner);
repoName = itemView.findViewById(R.id.repoName);
ImageView deleteDraft = itemView.findViewById(R.id.deleteDraft);
deleteDraft.setOnClickListener(itemDelete -> {
int getDraftId = Integer.parseInt(draftId.getText().toString());
deleteDraft(getAdapterPosition());
DraftsRepository.deleteSingleDraft(getDraftId);
});
draftText.setOnClickListener(itemEdit -> {
Intent intent = new Intent(mCtx, ReplyToIssueActivity.class);
intent.putExtra("commentBody", draftText.getText());
intent.putExtra("issueNumber", issueNumber.getText());
intent.putExtra("repositoryId", repoId.getText());
intent.putExtra("draftTitle", repoInfo.getText());
TinyDB tinyDb = new TinyDB(mCtx);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
tinyDb.putLong("repositoryId", Long.parseLong(repoId.getText().toString()));
//tinyDb.putString("issueType", issueType.getText().toString());
mCtx.startActivity(intent);
});
}
}
public DraftsAdapter(Context mCtx, List<DraftsWithRepositories> draftsListMain) {
this.mCtx = mCtx;
this.draftsList = draftsListMain;
}
private void deleteDraft(int position) {
draftsList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, draftsList.size());
Toasty.info(mCtx, mCtx.getResources().getString(R.string.draftsSingleDeleteSuccess));
}
@NonNull
@Override
public DraftsAdapter.DraftsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_drafts, parent, false);
return new DraftsViewHolder(v);
}
@SuppressLint("DefaultLocale")
@Override
public void onBindViewHolder(@NonNull DraftsAdapter.DraftsViewHolder holder, int position) {
DraftsWithRepositories currentItem = draftsList.get(position);
holder.repoId.setText(String.valueOf(currentItem.getRepositoryId()));
holder.draftId.setText(String.valueOf(currentItem.getDraftId()));
holder.issueNumber.setText(String.valueOf(currentItem.getIssueId()));
holder.issueType.setText(currentItem.getDraftType());
holder.repoOwner.setText(currentItem.getRepositoryOwner());
holder.repoName.setText(currentItem.getRepositoryName());
holder.draftText.setText(currentItem.getDraftText());
holder.repoInfo.setText(String.format("%s/%s %s%d", currentItem.getRepositoryOwner(), currentItem.getRepositoryName(), mCtx.getResources().getString(R.string.hash), currentItem.getIssueId()));
}