Merge branch 'release/1.0-beta20'
This commit is contained in:
		| @@ -20,8 +20,8 @@ android { | ||||
|         applicationId "ch.dissem.apps.${appName.toLowerCase()}" | ||||
|         minSdkVersion 19 | ||||
|         targetSdkVersion 27 | ||||
|         versionCode 19 | ||||
|         versionName "1.0-beta19" | ||||
|         versionCode 20 | ||||
|         versionName "1.0-beta20" | ||||
|         multiDexEnabled true | ||||
|     } | ||||
|     compileOptions { | ||||
|   | ||||
| @@ -19,8 +19,8 @@ package ch.dissem.apps.abit.listener | ||||
| import android.content.BroadcastReceiver | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import ch.dissem.apps.abit.service.BitmessageService | ||||
| import ch.dissem.apps.abit.service.Singleton | ||||
| import ch.dissem.apps.abit.util.NetworkUtils | ||||
| import ch.dissem.apps.abit.util.Preferences | ||||
| import org.jetbrains.anko.connectivityManager | ||||
|  | ||||
| @@ -29,7 +29,7 @@ class WifiReceiver : BroadcastReceiver() { | ||||
|         if ("android.net.conn.CONNECTIVITY_CHANGE" == intent.action) { | ||||
|             val bmc = Singleton.getBitmessageContext(ctx) | ||||
|             if (Preferences.isFullNodeActive(ctx) && !bmc.isRunning() && !(Preferences.isWifiOnly(ctx) && ctx.connectivityManager.isActiveNetworkMetered)) { | ||||
|                 ctx.startService(Intent(ctx, BitmessageService::class.java)) | ||||
|                 NetworkUtils.doStartBitmessageService(ctx) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -17,8 +17,13 @@ | ||||
| package ch.dissem.apps.abit.notification | ||||
|  | ||||
| import android.app.Notification | ||||
| import android.app.NotificationChannel | ||||
| import android.app.NotificationManager | ||||
| import android.content.Context | ||||
| import android.os.Build | ||||
| import android.support.annotation.ColorRes | ||||
| import android.support.v4.content.ContextCompat | ||||
| import ch.dissem.apps.abit.R | ||||
| import org.jetbrains.anko.notificationManager | ||||
|  | ||||
| /** | ||||
| @@ -46,4 +51,30 @@ abstract class AbstractNotification(ctx: Context) { | ||||
|         showing = false | ||||
|         manager.cancel(notificationId) | ||||
|     } | ||||
|  | ||||
|     protected fun initChannel(channelId: String, @ColorRes color: Int = R.color.colorPrimary) { | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             ctx.notificationManager.createNotificationChannel( | ||||
|                 NotificationChannel( | ||||
|                     channelId, | ||||
|                     ctx.getText(R.string.app_name), | ||||
|                     NotificationManager.IMPORTANCE_LOW | ||||
|                 ).apply { | ||||
|                     lightColor = ContextCompat.getColor(ctx, color) | ||||
|                     lockscreenVisibility = Notification.VISIBILITY_PRIVATE | ||||
|                 } | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     companion object { | ||||
|         internal const val ONGOING_CHANNEL_ID = "abit.ongoing" | ||||
|         internal const val MESSAGE_CHANNEL_ID = "abit.message" | ||||
|         internal const val ERROR_CHANNEL_ID = "abit.error" | ||||
|  | ||||
|         init { | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -30,10 +30,14 @@ import ch.dissem.apps.abit.R | ||||
|  */ | ||||
| class ErrorNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|  | ||||
|     private val builder = NotificationCompat.Builder(ctx, "abit.error") | ||||
|     private val builder = NotificationCompat.Builder(ctx, ERROR_CHANNEL_ID) | ||||
|         .setContentTitle(ctx.getString(R.string.app_name)) | ||||
|         .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|  | ||||
|     init { | ||||
|         initChannel(ERROR_CHANNEL_ID, R.color.colorPrimaryDark) | ||||
|     } | ||||
|  | ||||
|     fun setWarning(@StringRes resId: Int, vararg args: Any): ErrorNotification { | ||||
|         builder.setSmallIcon(R.drawable.ic_notification_warning) | ||||
|             .setContentText(ctx.getString(resId, *args)) | ||||
|   | ||||
| @@ -34,10 +34,11 @@ import kotlin.concurrent.fixedRateTimer | ||||
|  */ | ||||
| class NetworkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|  | ||||
|     private val builder = NotificationCompat.Builder(ctx, "abit.network") | ||||
|     private val builder = NotificationCompat.Builder(ctx, ONGOING_CHANNEL_ID) | ||||
|     private var timer: Timer? = null | ||||
|  | ||||
|     init { | ||||
|         initChannel(ONGOING_CHANNEL_ID, R.color.colorAccent) | ||||
|         val showAppIntent = Intent(ctx, MainActivity::class.java) | ||||
|         val pendingIntent = PendingIntent.getActivity(ctx, 1, showAppIntent, 0) | ||||
|         builder | ||||
| @@ -63,11 +64,19 @@ class NetworkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|                 val streamNumber = Integer.parseInt(stream.name.substring("stream ".length)) | ||||
|                 val nodeCount = stream.getProperty("nodes")!!.value as Int? | ||||
|                 if (nodeCount == 1) { | ||||
|                     info.append(ctx.getString(R.string.connection_info_1, | ||||
|                             streamNumber)) | ||||
|                     info.append( | ||||
|                         ctx.getString( | ||||
|                             R.string.connection_info_1, | ||||
|                             streamNumber | ||||
|                         ) | ||||
|                     ) | ||||
|                 } else { | ||||
|                     info.append(ctx.getString(R.string.connection_info_n, | ||||
|                             streamNumber, nodeCount)) | ||||
|                     info.append( | ||||
|                         ctx.getString( | ||||
|                             R.string.connection_info_n, | ||||
|                             streamNumber, nodeCount | ||||
|                         ) | ||||
|                     ) | ||||
|                 } | ||||
|                 info.append('\n') | ||||
|             } | ||||
| @@ -77,14 +86,18 @@ class NetworkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|         val intent = Intent(ctx, BitmessageIntentService::class.java) | ||||
|         if (running) { | ||||
|             intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true) | ||||
|             builder.addAction(R.drawable.ic_notification_node_stop, | ||||
|             builder.addAction( | ||||
|                 R.drawable.ic_notification_node_stop, | ||||
|                 ctx.getString(R.string.full_node_stop), | ||||
|                     PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT)) | ||||
|                 PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT) | ||||
|             ) | ||||
|         } else { | ||||
|             intent.putExtra(BitmessageIntentService.EXTRA_STARTUP_NODE, true) | ||||
|             builder.addAction(R.drawable.ic_notification_node_start, | ||||
|             builder.addAction( | ||||
|                 R.drawable.ic_notification_node_start, | ||||
|                 ctx.getString(R.string.full_node_restart), | ||||
|                     PendingIntent.getService(ctx, 1, intent, FLAG_UPDATE_CURRENT)) | ||||
|                 PendingIntent.getService(ctx, 1, intent, FLAG_UPDATE_CURRENT) | ||||
|             ) | ||||
|         } | ||||
|         notification = builder.build() | ||||
|         return running | ||||
| @@ -116,13 +129,15 @@ class NetworkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|         val intent = Intent(ctx, BitmessageIntentService::class.java) | ||||
|         intent.putExtra(BitmessageIntentService.EXTRA_SHUTDOWN_NODE, true) | ||||
|         builder.mActions.clear() | ||||
|         builder.addAction(R.drawable.ic_notification_node_stop, | ||||
|         builder.addAction( | ||||
|             R.drawable.ic_notification_node_stop, | ||||
|             ctx.getString(R.string.full_node_stop), | ||||
|                 PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT)) | ||||
|             PendingIntent.getService(ctx, 0, intent, FLAG_UPDATE_CURRENT) | ||||
|         ) | ||||
|         notification = builder.build() | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         val NETWORK_NOTIFICATION_ID = 2 | ||||
|         const val NETWORK_NOTIFICATION_ID = 2 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -42,8 +42,12 @@ import ch.dissem.apps.abit.util.Drawables.toBitmap | ||||
|  | ||||
| class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|  | ||||
|     init { | ||||
|         initChannel(MESSAGE_CHANNEL_ID, R.color.colorPrimary) | ||||
|     } | ||||
|  | ||||
|     fun singleNotification(plaintext: Plaintext): NewMessageNotification { | ||||
|         val builder = NotificationCompat.Builder(ctx, CHANNEL_ID) | ||||
|         val builder = NotificationCompat.Builder(ctx, MESSAGE_CHANNEL_ID) | ||||
|         val bigText = SpannableString(plaintext.subject + "\n" + plaintext.text) | ||||
|         plaintext.subject?.let { subject -> | ||||
|             bigText.setSpan(SPAN_EMPHASIS, 0, subject.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE) | ||||
| @@ -56,22 +60,30 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|             .setContentInfo("Info") | ||||
|  | ||||
|         builder.setContentIntent( | ||||
|                 createActivityIntent(EXTRA_SHOW_MESSAGE, plaintext)) | ||||
|         builder.addAction(R.drawable.ic_action_reply, ctx.getString(R.string.reply), | ||||
|                 createActivityIntent(EXTRA_REPLY_TO_MESSAGE, plaintext)) | ||||
|         builder.addAction(R.drawable.ic_action_delete, ctx.getString(R.string.delete), | ||||
|                 createServiceIntent(ctx, EXTRA_DELETE_MESSAGE, plaintext)) | ||||
|             createActivityIntent(EXTRA_SHOW_MESSAGE, plaintext) | ||||
|         ) | ||||
|         builder.addAction( | ||||
|             R.drawable.ic_action_reply, ctx.getString(R.string.reply), | ||||
|             createActivityIntent(EXTRA_REPLY_TO_MESSAGE, plaintext) | ||||
|         ) | ||||
|         builder.addAction( | ||||
|             R.drawable.ic_action_delete, ctx.getString(R.string.delete), | ||||
|             createServiceIntent(ctx, EXTRA_DELETE_MESSAGE, plaintext) | ||||
|         ) | ||||
|         notification = builder.build() | ||||
|         return this | ||||
|     } | ||||
|  | ||||
|     private fun createActivityIntent(action: String, message: Plaintext): PendingIntent { | ||||
|         val intent = Intent(ctx, MainActivity::class.java) | ||||
|         intent.putExtra(action, message) | ||||
|         val intent = Intent(ctx, MainActivity::class.java).putExtra(action, message) | ||||
|         return PendingIntent.getActivity(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT) | ||||
|     } | ||||
|  | ||||
|     private fun createServiceIntent(ctx: Context, action: String, message: Plaintext): PendingIntent { | ||||
|     private fun createServiceIntent( | ||||
|         ctx: Context, | ||||
|         action: String, | ||||
|         message: Plaintext | ||||
|     ): PendingIntent { | ||||
|         val intent = Intent(ctx, BitmessageIntentService::class.java) | ||||
|         intent.putExtra(action, message) | ||||
|         return PendingIntent.getService(ctx, action.hashCode(), intent, FLAG_UPDATE_CURRENT) | ||||
| @@ -82,8 +94,11 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|      * *                       accessed it will be in a `synchronized(unacknowledged) | ||||
|      * *                       {}` block | ||||
|      */ | ||||
|     fun multiNotification(unacknowledged: Collection<Plaintext>, numberOfUnacknowledgedMessages: Int): NewMessageNotification { | ||||
|         val builder = NotificationCompat.Builder(ctx, CHANNEL_ID) | ||||
|     fun multiNotification( | ||||
|         unacknowledged: Collection<Plaintext>, | ||||
|         numberOfUnacknowledgedMessages: Int | ||||
|     ): NewMessageNotification { | ||||
|         val builder = NotificationCompat.Builder(ctx, MESSAGE_CHANNEL_ID) | ||||
|         builder.setSmallIcon(R.drawable.ic_notification_new_message) | ||||
|             .setContentTitle(ctx.getString(R.string.n_new_messages, numberOfUnacknowledgedMessages)) | ||||
|             .setContentText(ctx.getString(R.string.app_name)) | ||||
| @@ -93,8 +108,10 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|         synchronized(unacknowledged) { | ||||
|             for (msg in unacknowledged) { | ||||
|                 val sb = SpannableString(msg.from.toString() + " " + msg.subject) | ||||
|                 sb.setSpan(SPAN_EMPHASIS, 0, msg.from.toString().length, Spannable | ||||
|                         .SPAN_INCLUSIVE_EXCLUSIVE) | ||||
|                 sb.setSpan( | ||||
|                     SPAN_EMPHASIS, 0, msg.from.toString().length, Spannable | ||||
|                         .SPAN_INCLUSIVE_EXCLUSIVE | ||||
|                 ) | ||||
|                 inboxStyle.addLine(sb) | ||||
|             } | ||||
|         } | ||||
| @@ -113,6 +130,5 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|     companion object { | ||||
|         private val NEW_MESSAGE_NOTIFICATION_ID = 1 | ||||
|         private val SPAN_EMPHASIS = StyleSpan(Typeface.BOLD) | ||||
|         private val CHANNEL_ID = "abit.message" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -33,7 +33,7 @@ import kotlin.concurrent.fixedRateTimer | ||||
|  */ | ||||
| class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|  | ||||
|     private val builder = NotificationCompat.Builder(ctx, "abit.pow") | ||||
|     private val builder = NotificationCompat.Builder(ctx, ONGOING_CHANNEL_ID) | ||||
|         .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|         .setUsesChronometer(true) | ||||
|         .setOngoing(true) | ||||
| @@ -46,6 +46,7 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|     private var timer: Timer? = null | ||||
|  | ||||
|     init { | ||||
|         initChannel(ONGOING_CHANNEL_ID, R.color.colorAccent) | ||||
|         update(0) | ||||
|     } | ||||
|  | ||||
| @@ -67,10 +68,6 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|         return this | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         const val ONGOING_NOTIFICATION_ID = 3 | ||||
|     } | ||||
|  | ||||
|     fun start(item: ProofOfWorkService.PowItem) { | ||||
|         val expectedPowTimeInMilliseconds = PowStats.getExpectedPowTimeInMilliseconds(ctx, item.targetValue) | ||||
|         val delta = (expectedPowTimeInMilliseconds / 3).toInt() | ||||
| @@ -101,4 +98,8 @@ class ProofOfWorkNotification(ctx: Context) : AbstractNotification(ctx) { | ||||
|             show() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         const val ONGOING_NOTIFICATION_ID = 3 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -25,6 +25,8 @@ import android.net.ConnectivityManager | ||||
| import android.os.Handler | ||||
| import ch.dissem.apps.abit.notification.NetworkNotification | ||||
| import ch.dissem.apps.abit.notification.NetworkNotification.Companion.NETWORK_NOTIFICATION_ID | ||||
| import ch.dissem.apps.abit.util.NetworkUtils | ||||
| import ch.dissem.apps.abit.util.Preferences | ||||
| import ch.dissem.bitmessage.BitmessageContext | ||||
| import ch.dissem.bitmessage.utils.Property | ||||
| import org.jetbrains.anko.connectivityManager | ||||
| @@ -40,8 +42,8 @@ class BitmessageService : Service() { | ||||
|     private lateinit var notification: NetworkNotification | ||||
|  | ||||
|     private val connectivityReceiver: BroadcastReceiver = object : BroadcastReceiver() { | ||||
|         override fun onReceive(context: Context?, intent: Intent?) { | ||||
|             if (bmc.isRunning() && connectivityManager.isActiveNetworkMetered){ | ||||
|         override fun onReceive(context: Context, intent: Intent?) { | ||||
|             if (bmc.isRunning() && !Preferences.isConnectionAllowed(this@BitmessageService)) { | ||||
|                 bmc.shutdown() | ||||
|             } | ||||
|         } | ||||
| @@ -58,7 +60,10 @@ class BitmessageService : Service() { | ||||
|     } | ||||
|  | ||||
|     override fun onCreate() { | ||||
|         registerReceiver(connectivityReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)) | ||||
|         registerReceiver( | ||||
|             connectivityReceiver, | ||||
|             IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION) | ||||
|         ) | ||||
|         notification = NetworkNotification(this) | ||||
|         running = false | ||||
|     } | ||||
| @@ -85,13 +90,15 @@ class BitmessageService : Service() { | ||||
|         notification.showShutdown() | ||||
|         cleanupHandler.removeCallbacks(cleanupTask) | ||||
|         bmc.cleanup() | ||||
|         unregisterReceiver(connectivityReceiver) | ||||
|         stopSelf() | ||||
|     } | ||||
|  | ||||
|     override fun onBind(intent: Intent) = null | ||||
|  | ||||
|     companion object { | ||||
|         @Volatile private var running = false | ||||
|         @Volatile | ||||
|         private var running = false | ||||
|  | ||||
|         val isRunning: Boolean | ||||
|             get() = running && Singleton.bitmessageContext?.isRunning() == true | ||||
|   | ||||
| @@ -20,6 +20,7 @@ import android.app.Service | ||||
| import android.content.Intent | ||||
| import android.os.Binder | ||||
| import android.os.IBinder | ||||
| import android.support.v4.content.ContextCompat | ||||
| import ch.dissem.apps.abit.notification.ProofOfWorkNotification | ||||
| import ch.dissem.apps.abit.notification.ProofOfWorkNotification.Companion.ONGOING_NOTIFICATION_ID | ||||
| import ch.dissem.apps.abit.util.PowStats | ||||
| @@ -44,9 +45,14 @@ class ProofOfWorkService : Service() { | ||||
|         private val notification = service.notification | ||||
|  | ||||
|         fun process(item: PowItem) = synchronized(queue) { | ||||
|             service.startService(Intent(service, ProofOfWorkService::class.java)) | ||||
|             service.startForeground(ONGOING_NOTIFICATION_ID, | ||||
|                 notification.notification) | ||||
|             ContextCompat.startForegroundService( | ||||
|                 service, | ||||
|                 Intent(service, ProofOfWorkService::class.java) | ||||
|             ) | ||||
|             service.startForeground( | ||||
|                 ONGOING_NOTIFICATION_ID, | ||||
|                 notification.notification | ||||
|             ) | ||||
|             if (!calculating) { | ||||
|                 calculating = true | ||||
|                 service.calculateNonce(item) | ||||
| @@ -58,7 +64,11 @@ class ProofOfWorkService : Service() { | ||||
|     } | ||||
|  | ||||
|  | ||||
|     data class PowItem(val initialHash: ByteArray, val targetValue: ByteArray, val callback: ProofOfWorkEngine.Callback) { | ||||
|     data class PowItem( | ||||
|         val initialHash: ByteArray, | ||||
|         val targetValue: ByteArray, | ||||
|         val callback: ProofOfWorkEngine.Callback | ||||
|     ) { | ||||
|         override fun equals(other: Any?): Boolean { | ||||
|             if (this === other) return true | ||||
|             if (javaClass != other?.javaClass) return false | ||||
| @@ -81,7 +91,10 @@ class ProofOfWorkService : Service() { | ||||
|     private fun calculateNonce(item: PowItem) { | ||||
|         notification.start(item) | ||||
|         val startTime = System.currentTimeMillis() | ||||
|         engine.calculateNonce(item.initialHash, item.targetValue, object : ProofOfWorkEngine.Callback { | ||||
|         engine.calculateNonce( | ||||
|             item.initialHash, | ||||
|             item.targetValue, | ||||
|             object : ProofOfWorkEngine.Callback { | ||||
|                 override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) { | ||||
|                     notification.finished() | ||||
|                     val time = System.currentTimeMillis() - startTime | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import android.app.job.JobService | ||||
| import android.content.Intent | ||||
| import android.os.Build | ||||
| import android.support.annotation.RequiresApi | ||||
| import ch.dissem.apps.abit.util.NetworkUtils | ||||
| import ch.dissem.apps.abit.util.Preferences | ||||
|  | ||||
| /** | ||||
| @@ -19,7 +20,7 @@ class StartupNodeOnWifiService : JobService() { | ||||
|     override fun onStartJob(params: JobParameters?): Boolean { | ||||
|         val bmc = Singleton.getBitmessageContext(this) | ||||
|         if (Preferences.isFullNodeActive(this) && !bmc.isRunning()) { | ||||
|             applicationContext.startService(Intent(this, BitmessageService::class.java)) | ||||
|             NetworkUtils.doStartBitmessageService(applicationContext) | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.os.Build | ||||
| import android.support.annotation.RequiresApi | ||||
| import android.support.v4.content.ContextCompat | ||||
| import ch.dissem.apps.abit.MainActivity | ||||
| import ch.dissem.apps.abit.dialog.FullNodeDialogActivity | ||||
| import ch.dissem.apps.abit.service.BitmessageService | ||||
| @@ -23,7 +24,7 @@ object NetworkUtils { | ||||
|                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | ||||
|                     scheduleNodeStart(ctx) | ||||
|                 } else { | ||||
|                     ctx.startService(Intent(ctx, BitmessageService::class.java)) | ||||
|                     doStartBitmessageService(ctx) | ||||
|                     MainActivity.updateNodeSwitch() | ||||
|                 } | ||||
|             } else if (ask) { | ||||
| @@ -37,11 +38,15 @@ object NetworkUtils { | ||||
|                 scheduleNodeStart(ctx) | ||||
|             } | ||||
|         } else { | ||||
|             ctx.startService(Intent(ctx, BitmessageService::class.java)) | ||||
|             doStartBitmessageService(ctx) | ||||
|             MainActivity.updateNodeSwitch() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun doStartBitmessageService(ctx: Context) { | ||||
|         ContextCompat.startForegroundService(ctx, Intent(ctx, BitmessageService::class.java)) | ||||
|     } | ||||
|  | ||||
|     fun disableNode(ctx: Context) { | ||||
|         Preferences.setFullNodeActive(ctx, false) | ||||
|         ctx.stopService(Intent(ctx, BitmessageService::class.java)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user