diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 19cfb5c7..2fc3c044 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -153,6 +153,9 @@ + diff --git a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java index b4340591..4ddf036b 100644 --- a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java @@ -15,6 +15,7 @@ import org.acra.data.StringFormat; import org.mian.gitnex.R; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.FontsOverride; +import org.mian.gitnex.helpers.StaticGlobalVariables; import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.notifications.NotificationsMaster; @@ -115,9 +116,9 @@ public abstract class BaseActivity extends AppCompatActivity { } - if(tinyDB.getInt("pollingDelayMinutes") == 0) { + if(tinyDB.getInt("pollingDelayMinutes", 0) <= 0) { - tinyDB.putInt("pollingDelayMinutes", 15); + tinyDB.putInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay); } // FIXME Performance nightmare diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsNotificationsActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsNotificationsActivity.java new file mode 100644 index 00000000..2d6ed1f3 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/activities/SettingsNotificationsActivity.java @@ -0,0 +1,123 @@ +package org.mian.gitnex.activities; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.View; +import android.widget.NumberPicker; +import androidx.appcompat.app.AlertDialog; +import com.pes.androidmaterialcolorpickerdialog.ColorPicker; +import org.mian.gitnex.R; +import org.mian.gitnex.databinding.ActivitySettingsNotificationsBinding; +import org.mian.gitnex.helpers.StaticGlobalVariables; +import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.notifications.NotificationsMaster; + +/** + * Template Author M M Arif + * Author opyale + */ + +public class SettingsNotificationsActivity extends BaseActivity { + + private ActivitySettingsNotificationsBinding viewBinding; + + @Override + protected int getLayoutResourceId() { + + return R.layout.activity_settings_notifications; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + viewBinding = ActivitySettingsNotificationsBinding.inflate(getLayoutInflater()); + View view = viewBinding.getRoot(); + setContentView(view); + + View.OnClickListener onClickListener = viewClose -> finish(); + + viewBinding.close.setOnClickListener(onClickListener); + + viewBinding.pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay))); + viewBinding.chooseColorState.setCardBackgroundColor(tinyDB.getInt("notificationsLightColor", Color.GREEN)); + + viewBinding.enableNotificationsMode.setChecked(tinyDB.getBoolean("notificationsEnabled", true)); + viewBinding.enableLightsMode.setChecked(tinyDB.getBoolean("notificationsEnableLights", true)); + viewBinding.enableVibrationMode.setChecked(tinyDB.getBoolean("notificationsEnableVibration", true)); + + viewBinding.enableNotificationsMode.setOnCheckedChangeListener((buttonView, isChecked) -> { + + tinyDB.putBoolean("notificationsEnabled", isChecked); + if(!isChecked) NotificationsMaster.fireWorker(ctx); + Toasty.info(appCtx, getResources().getString(R.string.settingsSave)); + + }); + + // polling delay + viewBinding.pollingDelayFrame.setOnClickListener(v -> { + + NumberPicker numberPicker = new NumberPicker(ctx); + numberPicker.setMinValue(StaticGlobalVariables.minimumPollingDelay); + numberPicker.setMaxValue(StaticGlobalVariables.maximumPollingDelay); + numberPicker.setValue(tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay)); + numberPicker.setWrapSelectorWheel(true); + + AlertDialog.Builder builder = new AlertDialog.Builder(ctx); + builder.setTitle(getString(R.string.pollingDelayDialogHeaderText)); + builder.setMessage(getString(R.string.pollingDelayDialogDescriptionText)); + + builder.setCancelable(true); + builder.setPositiveButton(getString(R.string.okButton), (dialog, which) -> { + + tinyDB.putInt("pollingDelayMinutes", numberPicker.getValue()); + + NotificationsMaster.fireWorker(ctx); + NotificationsMaster.hireWorker(ctx); + + viewBinding.pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), numberPicker.getValue())); + Toasty.info(appCtx, getResources().getString(R.string.settingsSave)); + }); + + builder.setNegativeButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss()); + builder.setView(numberPicker); + builder.create().show(); + }); + + // lights switcher + viewBinding.enableLightsMode.setOnCheckedChangeListener((buttonView, isChecked) -> { + + tinyDB.putBoolean("notificationsEnableLights", isChecked); + Toasty.info(appCtx, getResources().getString(R.string.settingsSave)); + + }); + + // lights color chooser + viewBinding.chooseColorFrame.setOnClickListener(v -> { + + ColorPicker colorPicker = new ColorPicker(SettingsNotificationsActivity.this); + colorPicker.setColor(tinyDB.getInt("notificationsLightColor", Color.GREEN)); + colorPicker.setCallback(color -> { + + tinyDB.putInt("notificationsLightColor", color); + viewBinding.chooseColorState.setCardBackgroundColor(color); + colorPicker.dismiss(); + Toasty.info(appCtx, getResources().getString(R.string.settingsSave)); + }); + + colorPicker.show(); + + }); + + // vibration switcher + viewBinding.enableVibrationMode.setOnCheckedChangeListener((buttonView, isChecked) -> { + + tinyDB.putBoolean("notificationsEnableVibration", isChecked); + Toasty.info(appCtx, getResources().getString(R.string.settingsSave)); + + }); + + } + +} diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java index cf09d265..6337d7d4 100644 --- a/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java @@ -7,15 +7,12 @@ import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.NumberPicker; import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import org.apache.commons.io.FileUtils; import org.mian.gitnex.R; import org.mian.gitnex.helpers.Toasty; -import org.mian.gitnex.helpers.Version; import org.mian.gitnex.helpers.ssl.MemorizingTrustManager; -import org.mian.gitnex.notifications.NotificationsMaster; import java.io.File; import java.io.IOException; @@ -27,16 +24,12 @@ public class SettingsSecurityActivity extends BaseActivity { private View.OnClickListener onClickListener; - private static String[] cacheSizeDataList = {"50 MB", "100 MB", "250 MB", "500 MB", "1 GB"}; + private static final String[] cacheSizeDataList = {"50 MB", "100 MB", "250 MB", "500 MB", "1 GB"}; private static int cacheSizeDataSelectedChoice = 0; - private static String[] cacheSizeImagesList = {"50 MB", "100 MB", "250 MB", "500 MB", "1 GB"}; + private static final String[] cacheSizeImagesList = {"50 MB", "100 MB", "250 MB", "500 MB", "1 GB"}; private static int cacheSizeImagesSelectedChoice = 0; - private static int MINIMUM_POLLING_DELAY = 1; - private static int DEFAULT_POLLING_DELAY = 20; - private static int MAXIMUM_POLLING_DELAY = 720; - @Override protected int getLayoutResourceId() { @@ -48,8 +41,6 @@ public class SettingsSecurityActivity extends BaseActivity { super.onCreate(savedInstanceState); - String currentVersion = tinyDB.getString("giteaVersion"); - ImageView closeActivity = findViewById(R.id.close); initCloseListener(); @@ -58,10 +49,8 @@ public class SettingsSecurityActivity extends BaseActivity { TextView cacheSizeDataSelected = findViewById(R.id.cacheSizeDataSelected); // setter for data cache size TextView cacheSizeImagesSelected = findViewById(R.id.cacheSizeImagesSelected); // setter for images cache size TextView clearCacheSelected = findViewById(R.id.clearCacheSelected); // setter for clear cache - TextView pollingDelaySelected = findViewById(R.id.pollingDelaySelected); LinearLayout certsFrame = findViewById(R.id.certsFrame); - LinearLayout pollingDelayFrame = findViewById(R.id.pollingDelayFrame); LinearLayout cacheSizeDataFrame = findViewById(R.id.cacheSizeDataSelectionFrame); LinearLayout cacheSizeImagesFrame = findViewById(R.id.cacheSizeImagesSelectionFrame); LinearLayout clearCacheFrame = findViewById(R.id.clearCacheSelectionFrame); @@ -86,13 +75,6 @@ public class SettingsSecurityActivity extends BaseActivity { cacheSizeImagesSelectedChoice = tinyDB.getInt("cacheSizeImagesId"); } - if(new Version(currentVersion).less("1.12.3")) { - - pollingDelayFrame.setVisibility(View.GONE); - } - - pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), tinyDB.getInt("pollingDelayMinutes", DEFAULT_POLLING_DELAY))); - // clear cache setter File cacheDir = appCtx.getCacheDir(); clearCacheSelected.setText(FileUtils.byteCountToDisplaySize((int) FileUtils.sizeOfDirectory(cacheDir))); @@ -193,36 +175,6 @@ public class SettingsSecurityActivity extends BaseActivity { builder.setNeutralButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss()); builder.create().show(); }); - - // polling delay - pollingDelayFrame.setOnClickListener(v -> { - - NumberPicker numberPicker = new NumberPicker(ctx); - numberPicker.setMinValue(MINIMUM_POLLING_DELAY); - numberPicker.setMaxValue(MAXIMUM_POLLING_DELAY); - numberPicker.setValue(tinyDB.getInt("pollingDelayMinutes", DEFAULT_POLLING_DELAY)); - numberPicker.setWrapSelectorWheel(true); - - AlertDialog.Builder builder = new AlertDialog.Builder(ctx); - builder.setTitle(getString(R.string.pollingDelayDialogHeaderText)); - builder.setMessage(getString(R.string.pollingDelayDialogDescriptionText)); - - builder.setCancelable(true); - builder.setPositiveButton(getString(R.string.okButton), (dialog, which) -> { - - tinyDB.putInt("pollingDelayMinutes", numberPicker.getValue()); - - NotificationsMaster.fireWorker(ctx); - NotificationsMaster.hireWorker(ctx); - - pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), numberPicker.getValue())); - Toasty.success(appCtx, getResources().getString(R.string.settingsSave)); - }); - - builder.setNeutralButton(R.string.cancelButton, null); - builder.setView(numberPicker); - builder.create().show(); - }); } private void initCloseListener() { diff --git a/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java index c70cdb5b..45f2f1fa 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java @@ -1,6 +1,7 @@ package org.mian.gitnex.fragments; import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -17,10 +18,12 @@ import org.mian.gitnex.activities.SettingsAppearanceActivity; import org.mian.gitnex.activities.SettingsDraftsActivity; import org.mian.gitnex.activities.SettingsFileViewerActivity; import org.mian.gitnex.activities.SettingsGeneralActivity; +import org.mian.gitnex.activities.SettingsNotificationsActivity; import org.mian.gitnex.activities.SettingsReportsActivity; import org.mian.gitnex.activities.SettingsSecurityActivity; import org.mian.gitnex.activities.SettingsTranslationActivity; import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Version; /** * Author M M Arif @@ -28,11 +31,16 @@ import org.mian.gitnex.helpers.TinyDB; public class SettingsFragment extends Fragment { + private Context ctx; + private TinyDB tinyDB; + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_settings, container, false); + ctx = getContext(); + tinyDB = TinyDB.getInstance(ctx); ((MainActivity) requireActivity()).setActionBarTitle(getResources().getString(R.string.navSettings)); @@ -41,39 +49,48 @@ public class SettingsFragment extends Fragment { LinearLayout fileViewerFrame = v.findViewById(R.id.fileViewerFrame); LinearLayout draftsFrame = v.findViewById(R.id.draftsFrame); LinearLayout securityFrame = v.findViewById(R.id.securityFrame); + LinearLayout notificationsFrame = v.findViewById(R.id.notificationsFrame); LinearLayout languagesFrame = v.findViewById(R.id.languagesFrame); LinearLayout reportsFrame = v.findViewById(R.id.reportsFrame); LinearLayout rateAppFrame = v.findViewById(R.id.rateAppFrame); LinearLayout aboutAppFrame = v.findViewById(R.id.aboutAppFrame); - generalFrame.setOnClickListener(generalFrameCall -> startActivity(new Intent(getContext(), SettingsGeneralActivity.class))); + if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.3")) { - appearanceFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), SettingsAppearanceActivity.class))); + notificationsFrame.setVisibility(View.VISIBLE); + } - fileViewerFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), SettingsFileViewerActivity.class))); + generalFrame.setOnClickListener(generalFrameCall -> startActivity(new Intent(ctx, SettingsGeneralActivity.class))); - draftsFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), SettingsDraftsActivity.class))); + appearanceFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsAppearanceActivity.class))); - securityFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), SettingsSecurityActivity.class))); + fileViewerFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsFileViewerActivity.class))); - languagesFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), SettingsTranslationActivity.class))); + draftsFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsDraftsActivity.class))); - reportsFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), SettingsReportsActivity.class))); + securityFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsSecurityActivity.class))); + + notificationsFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsNotificationsActivity.class))); + + languagesFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsTranslationActivity.class))); + + reportsFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsReportsActivity.class))); rateAppFrame.setOnClickListener(aboutApp -> rateThisApp()); aboutAppFrame.setOnClickListener(aboutApp -> requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).commit()); return v; - } public void rateThisApp() { try { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + requireActivity().getPackageName()))); } catch(ActivityNotFoundException e) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + requireActivity().getPackageName()))); } } @@ -83,14 +100,12 @@ public class SettingsFragment extends Fragment { super.onResume(); - TinyDB tinyDb = TinyDB.getInstance(getContext()); + if(tinyDB.getBoolean("refreshParent")) { - if(tinyDb.getBoolean("refreshParent")) { requireActivity().recreate(); requireActivity().overridePendingTransition(0, 0); - tinyDb.putBoolean("refreshParent", false); + tinyDB.putBoolean("refreshParent", false); } - } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/StarredRepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/StarredRepositoriesFragment.java index c54d5725..f6a98785 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/StarredRepositoriesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/StarredRepositoriesFragment.java @@ -92,14 +92,10 @@ public class StarredRepositoriesFragment extends Fragment { createNewRepo = v.findViewById(R.id.addNewRepo); - createNewRepo.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View view) { - Intent intent = new Intent(view.getContext(), CreateRepoActivity.class); - startActivity(intent); - } + createNewRepo.setOnClickListener(view -> { + Intent intent = new Intent(view.getContext(), CreateRepoActivity.class); + startActivity(intent); }); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @@ -133,6 +129,7 @@ public class StarredRepositoriesFragment extends Fragment { @Override public void onResume() { + super.onResume(); TinyDB tinyDb = TinyDB.getInstance(getContext()); final String loginUid = tinyDb.getString("loginUid"); diff --git a/app/src/main/java/org/mian/gitnex/helpers/StaticGlobalVariables.java b/app/src/main/java/org/mian/gitnex/helpers/StaticGlobalVariables.java index 9a3a7906..2af5e693 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/StaticGlobalVariables.java +++ b/app/src/main/java/org/mian/gitnex/helpers/StaticGlobalVariables.java @@ -46,4 +46,8 @@ public abstract class StaticGlobalVariables { public static String draftTypeIssue = "Issue"; public static String draftTypePull = "Pull"; + // polling - notifications + public static int minimumPollingDelay = 1; + public static int defaultPollingDelay = 15; + public static int maximumPollingDelay = 720; } diff --git a/app/src/main/java/org/mian/gitnex/notifications/NotificationsMaster.java b/app/src/main/java/org/mian/gitnex/notifications/NotificationsMaster.java index aa737bac..aca4981e 100644 --- a/app/src/main/java/org/mian/gitnex/notifications/NotificationsMaster.java +++ b/app/src/main/java/org/mian/gitnex/notifications/NotificationsMaster.java @@ -7,6 +7,7 @@ import androidx.work.ExistingPeriodicWorkPolicy; import androidx.work.NetworkType; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; +import org.mian.gitnex.helpers.StaticGlobalVariables; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Version; import java.util.concurrent.TimeUnit; @@ -38,30 +39,33 @@ public class NotificationsMaster { TinyDB tinyDB = TinyDB.getInstance(context); - if(notificationsSupported == -1) { - checkVersion(tinyDB); - } + if(tinyDB.getBoolean("notificationsEnabled", true)) { - if(notificationsSupported == 1) { + if(notificationsSupported == -1) checkVersion(tinyDB); - Constraints.Builder constraints = new Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .setRequiresBatteryNotLow(false) - .setRequiresStorageNotLow(false) - .setRequiresCharging(false); + if(notificationsSupported == 1) { - if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Constraints.Builder constraints = new Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .setRequiresBatteryNotLow(false) + .setRequiresStorageNotLow(false) + .setRequiresCharging(false); + + if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + + constraints.setRequiresDeviceIdle(false); + } + + int pollingDelayMinutes = Math.max(tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay), 15); + + PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(NotificationsWorker.class, pollingDelayMinutes, TimeUnit.MINUTES) + .setConstraints(constraints.build()) + .addTag(context.getPackageName()) + .build(); + + WorkManager.getInstance(context).enqueueUniquePeriodicWork(context.getPackageName(), ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest); - constraints.setRequiresDeviceIdle(false); } - - PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(NotificationsWorker.class, tinyDB.getInt("pollingDelayMinutes"), TimeUnit.MINUTES) - .setConstraints(constraints.build()) - .addTag(context.getPackageName()) - .build(); - - WorkManager.getInstance(context).enqueueUniquePeriodicWork(context.getPackageName(), ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest); - } } } diff --git a/app/src/main/java/org/mian/gitnex/notifications/NotificationsWorker.java b/app/src/main/java/org/mian/gitnex/notifications/NotificationsWorker.java index 0c2e413a..b7e13062 100644 --- a/app/src/main/java/org/mian/gitnex/notifications/NotificationsWorker.java +++ b/app/src/main/java/org/mian/gitnex/notifications/NotificationsWorker.java @@ -1,5 +1,6 @@ package org.mian.gitnex.notifications; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; @@ -11,12 +12,14 @@ import android.os.Build; import android.util.Log; import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; import androidx.work.Worker; import androidx.work.WorkerParameters; import org.mian.gitnex.R; import org.mian.gitnex.activities.MainActivity; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.StaticGlobalVariables; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.models.NotificationThread; import java.util.Date; @@ -42,7 +45,6 @@ public class NotificationsWorker extends Worker { this.context = context; this.tinyDB = TinyDB.getInstance(context); - } @NonNull @@ -51,7 +53,7 @@ public class NotificationsWorker extends Worker { String token = "token " + tinyDB.getString(tinyDB.getString("loginUid") + "-token"); - int notificationLoops = tinyDB.getInt("pollingDelayMinutes") >= 15 ? 1 : Math.min(15 - tinyDB.getInt("pollingDelayMinutes"), 10); + int notificationLoops = tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay) >= 15 ? 1 : Math.min(15 - tinyDB.getInt("pollingDelayMinutes"), 10); for(int i=0; i notificationThreads = response.body(); - Log.i("ReceivedNotifications", String.valueOf(notificationThreads.size())); if(!notificationThreads.isEmpty()) { - for(NotificationThread notificationThread : notificationThreads) { - - sendNotification(notificationThread); - } + sendNotification(notificationThreads); } tinyDB.putString("previousRefreshTimestamp", AppUtil.getTimestampFromDate(context, new Date())); - - } else { + } + else { Log.e("onError", String.valueOf(response.code())); } - } catch(Exception e) { + } + catch(Exception e) { Log.e("onError", e.toString()); } @@ -100,60 +99,125 @@ public class NotificationsWorker extends Worker { Thread.sleep(60000 - (System.currentTimeMillis() - startPollingTime)); } - } catch (InterruptedException ignored) {} + } + catch (InterruptedException ignored) {} } return Result.success(); - } - private void sendNotification(NotificationThread notificationThread) { + private void sendNotification(List notificationThreads) { + + int summaryId = 0; + PendingIntent pendingIntent = getPendingIntent(); + + NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context); + attachNotificationChannel(notificationManagerCompat); + + Notification summaryNotification = new NotificationCompat.Builder(context, context.getPackageName()) + .setContentTitle(context.getString(R.string.newMessages)) + .setContentText(String.format(context.getString(R.string.youHaveGotNewNotifications), notificationThreads.size())) + .setSmallIcon(R.drawable.gitnex_transparent) + .setGroup(context.getPackageName()) + .setGroupSummary(true) + .setAutoCancel(true) + .setContentIntent(pendingIntent) + .build(); + + notificationManagerCompat.notify(summaryId, summaryNotification); + + for(NotificationThread notificationThread : notificationThreads) { + + NotificationManagerCompat notificationManagerCompat1 = NotificationManagerCompat.from(context); + attachNotificationChannel(notificationManagerCompat1); + + String subjectUrl = notificationThread.getSubject().getUrl(); + String issueId = context.getResources().getString(R.string.hash) + subjectUrl.substring(subjectUrl.lastIndexOf("/") + 1); + String notificationHeader = issueId + " " + notificationThread.getSubject().getTitle() + " " + String.format(context.getResources().getString(R.string.notificationExtraInfo), notificationThread.getRepository().getFull_name(), notificationThread.getSubject().getType()); + + NotificationCompat.Builder builder1 = getBaseNotificationBuilder() + .setContentTitle(notificationHeader) + .setGroup(context.getPackageName()) + .setContentIntent(pendingIntent); + + pushNotification(notificationManagerCompat1, builder1.build()); + } + } + + private void pushNotification(NotificationManagerCompat notificationManagerCompat, Notification notification) { + + int previousNotificationId = tinyDB.getInt("previousNotificationId", 0); + int nextPreviousNotificationId = previousNotificationId > 71951418 ? 0 : previousNotificationId + 1; + + tinyDB.putInt("previousNotificationId", nextPreviousNotificationId); + notificationManagerCompat.notify(previousNotificationId, notification); + } + + private void attachNotificationChannel(NotificationManagerCompat notificationManagerCompat) { + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + + NotificationChannel notificationChannel = new NotificationChannel(context.getPackageName(), context.getString(R.string.app_name), + NotificationManager.IMPORTANCE_DEFAULT); + + notificationChannel.setDescription(context.getString(R.string.notificationChannelDescription)); + + if(tinyDB.getBoolean("notificationsEnableVibration", true)) { + + notificationChannel.setVibrationPattern(VIBRATION_PATTERN); + notificationChannel.enableVibration(true); + } + else { + + notificationChannel.enableVibration(false); + } + + if(tinyDB.getBoolean("notificationsEnableLights", true)) { + + notificationChannel.setLightColor(tinyDB.getInt("notificationsLightColor", Color.GREEN)); + notificationChannel.enableLights(true); + } + else { + + notificationChannel.enableLights(false); + } + + notificationManagerCompat.createNotificationChannel(notificationChannel); + } + } + + private NotificationCompat.Builder getBaseNotificationBuilder() { + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, context.getPackageName()) + .setSmallIcon(R.drawable.gitnex_transparent) + .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) + .setCategory(NotificationCompat.CATEGORY_MESSAGE) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setAutoCancel(true); + + if(tinyDB.getBoolean("notificationsEnableLights", true)) { + + builder.setLights(tinyDB.getInt("notificationsLightColor", Color.GREEN), 1500, 1500); + } + + if(tinyDB.getBoolean("notificationsEnableVibration", true)) { + + builder.setVibrate(VIBRATION_PATTERN); + } + else { + + builder.setVibrate(null); + } + + return builder; + } + + private PendingIntent getPendingIntent() { Intent intent = new Intent(context, MainActivity.class); intent.putExtra("launchFragment", "notifications"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - - if(notificationManager != null) { - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - - NotificationChannel notificationChannel = new NotificationChannel(context.getPackageName(), context.getString(R.string.app_name), - NotificationManager.IMPORTANCE_HIGH); - - notificationChannel.enableLights(true); - notificationChannel.setLightColor(Color.GREEN); - notificationChannel.enableVibration(true); - notificationChannel.setVibrationPattern(VIBRATION_PATTERN); - - notificationManager.createNotificationChannel(notificationChannel); - - } - - String subjectUrl = notificationThread.getSubject().getUrl(); - String issueId = context.getResources().getString(R.string.hash) + subjectUrl.substring(subjectUrl.lastIndexOf("/") + 1); - - String notificationHeader = issueId + " " + notificationThread.getSubject().getTitle(); - String notificationBody = String.format(context.getResources().getString(R.string.notificationBody), - notificationThread.getSubject().getType()); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(context, context.getPackageName()) - .setSmallIcon(R.drawable.gitnex_transparent).setContentTitle(notificationHeader) - .setContentText(notificationBody) - .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setContentIntent(pendingIntent).setVibrate(VIBRATION_PATTERN).setAutoCancel(true); - - int previousNotificationId = tinyDB.getInt("previousNotificationId", 0); - int newPreviousNotificationId = previousNotificationId > 71951418 ? 0 : previousNotificationId + 1; - - tinyDB.putInt("previousNotificationId", newPreviousNotificationId); - - notificationManager.notify(previousNotificationId, builder.build()); - - } + return PendingIntent.getActivity(context, 0, intent, 0); } - } diff --git a/app/src/main/res/layout/activity_settings_notifications.xml b/app/src/main/res/layout/activity_settings_notifications.xml new file mode 100644 index 00000000..404246f3 --- /dev/null +++ b/app/src/main/res/layout/activity_settings_notifications.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_settings_security.xml b/app/src/main/res/layout/activity_settings_security.xml index 5701525e..578f248b 100644 --- a/app/src/main/res/layout/activity_settings_security.xml +++ b/app/src/main/res/layout/activity_settings_security.xml @@ -153,34 +153,4 @@ - - - - - - - - diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 5228cb87..353a9c7c 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -177,6 +177,39 @@ + + + + + + + + Themes, fonts, badges PDF mode, source code theme - SSL certificates, cache, polling delay + SSL certificates, cache Languages Crash reports If you like GitNex you can give it a thumbs up @@ -662,18 +662,23 @@ Notifications No notifications found - - You have received a new notification. (%s) - Notifications Polling Delay %d Minutes Select Polling Delay Choose a minutely delay in which GitNex tries to poll new notifications - Mark as Read Mark as Unread Pin Notification Successfully marked all notifications as read + Polling delay, light, vibration + Enable Notifications + Enable Light + Enable Vibration + Choose Color + New messages + You\'ve got %d new notifications. + This is the main notification channel of GitNex. + - %s (%s) Read Unread diff --git a/app/src/test/java/org/mian/gitnex/helpers/PathsHelperTest.java b/app/src/test/java/org/mian/gitnex/helpers/PathsHelperTest.java new file mode 100644 index 00000000..3443ee61 --- /dev/null +++ b/app/src/test/java/org/mian/gitnex/helpers/PathsHelperTest.java @@ -0,0 +1,34 @@ +package org.mian.gitnex.helpers; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * Author opyale + */ + +public class PathsHelperTest { + + @Test + public void testJoin() { + + assertEquals(PathsHelper.join("test", "/test", "test/", "/test/"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("test", "test", "test", "test"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("/test", "/test", "/test", "/test"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("/test/", "/test/", "test/", "/test/"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("test", "test", "/test", "/test"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("test/", "test", "/test", "/test"), "/test/test/test/test/"); + + assertEquals(PathsHelper.join("test/test/test/test"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("/test/test/test/test"), "/test/test/test/test/"); + assertEquals(PathsHelper.join("test/test/test/test/"), "/test/test/test/test/"); + + assertEquals(PathsHelper.join("test"), "/test/"); + assertEquals(PathsHelper.join("test/"), "/test/"); + assertEquals(PathsHelper.join("/test/"), "/test/"); + assertEquals(PathsHelper.join("/test"), "/test/"); + + } + +} + diff --git a/app/src/test/java/org/mian/gitnex/helpers/VersionTest.java b/app/src/test/java/org/mian/gitnex/helpers/VersionTest.java index 4d60e594..34bada6b 100644 --- a/app/src/test/java/org/mian/gitnex/helpers/VersionTest.java +++ b/app/src/test/java/org/mian/gitnex/helpers/VersionTest.java @@ -1,13 +1,13 @@ package org.mian.gitnex.helpers; -/** - * Author 6543 - */ - import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +/** + * Author 6543 + */ + public class VersionTest { @Test diff --git a/gradle.properties b/gradle.properties index d546deaf..ed7c758a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ # The setting is particularly useful for tweaking memory settings. android.enableJetifier=true android.useAndroidX=true -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects