Compare commits
6 Commits
03c2cd813d
...
28ccc29512
Author | SHA1 | Date |
---|---|---|
majestrate | 28ccc29512 | |
frtget | cd8d515038 | |
frtget | 5f45a9f743 | |
frtget | 5d50451c3b | |
frtget | cc7c93d179 | |
frtget | bfdb8b1316 |
|
@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
|||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 31
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name="io.flutter.app.FlutterApplication"
|
||||
android:name="${applicationName}"
|
||||
android:label="Lokinet"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
@ -32,15 +32,6 @@
|
|||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<!-- Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
gap between the end of Android's launch screen and the painting of
|
||||
Flutter's first frame. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath "com.android.tools.build:gradle:7.0.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:lokinet_lib/lokinet_lib.dart';
|
||||
import 'package:lokinet_mobile/src/settings.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_dakmode.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_darkmode.dart';
|
||||
import 'package:lokinet_mobile/src/widget/lokinet_divider.dart';
|
||||
import 'package:lokinet_mobile/src/widget/lokinet_power_button.dart';
|
||||
import 'package:lokinet_mobile/src/widget/themed_lokinet_logo.dart';
|
||||
|
@ -87,14 +87,14 @@ class MyForm extends StatefulWidget {
|
|||
|
||||
class MyFormState extends State<MyForm> {
|
||||
static final key = new GlobalKey<FormState>();
|
||||
Timer _timer;
|
||||
bool isConnected = false;
|
||||
|
||||
void _startTimer() {
|
||||
const halfSec = Duration(milliseconds: 50);
|
||||
_timer = Timer.periodic(halfSec, (Timer timer) async {
|
||||
await _updateLokinetStatus();
|
||||
});
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
LokinetLib.onStatusUpdate((bool status) => setState(() {
|
||||
isConnected = status;
|
||||
}));
|
||||
}
|
||||
|
||||
Future _updateLokinetStatus() async {
|
||||
|
@ -104,18 +104,12 @@ class MyFormState extends State<MyForm> {
|
|||
});
|
||||
}
|
||||
|
||||
Future _cancelTimer() async {
|
||||
await _updateLokinetStatus();
|
||||
if (_timer != null) _timer.cancel();
|
||||
}
|
||||
|
||||
Future toogleLokinet() async {
|
||||
Future toggleLokinet() async {
|
||||
if (!key.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
if (await LokinetLib.isRunning) {
|
||||
await LokinetLib.disconnectFromLokinet();
|
||||
await _cancelTimer();
|
||||
} else {
|
||||
//Save the exit node and upstream dns
|
||||
final Settings settings = Settings.getInstance();
|
||||
|
@ -126,7 +120,6 @@ class MyFormState extends State<MyForm> {
|
|||
if (result)
|
||||
LokinetLib.connectToLokinet(
|
||||
exitNode: settings.exitNode, upstreamDNS: settings.upstreamDNS);
|
||||
_startTimer();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +133,7 @@ class MyFormState extends State<MyForm> {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
LokinetPowerButton(toogleLokinet),
|
||||
LokinetPowerButton(toggleLokinet),
|
||||
LokinetDivider(),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 45, right: 45),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_dakmode.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_darkmode.dart';
|
||||
|
||||
class LokinetDivider extends StatelessWidget {
|
||||
final String _ending;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_dakmode.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_darkmode.dart';
|
||||
|
||||
class LokinetPowerButton extends StatelessWidget {
|
||||
final VoidCallback onPressed;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_dakmode.dart';
|
||||
import 'package:lokinet_mobile/src/utils/is_darkmode.dart';
|
||||
|
||||
class ThemedLokinetLogo extends StatelessWidget {
|
||||
@override
|
||||
|
|
|
@ -2,7 +2,7 @@ group "io.oxen.lokinet_lib"
|
|||
version "1.0-SNAPSHOT"
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = "1.3.50"
|
||||
ext.kotlin_version = "1.6.10"
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
@ -12,7 +12,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:3.5.0"
|
||||
classpath "com.android.tools.build:gradle:7.0.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.diffplug.spotless:spotless-plugin-gradle:5.14.0"
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ spotless {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 31
|
||||
|
||||
ndkVersion '21.3.6528147'
|
||||
sourceSets {
|
||||
|
|
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||
|
|
|
@ -13,7 +13,7 @@ public class LokinetConfig {
|
|||
|
||||
/*** load config file from disk */
|
||||
public native boolean Load();
|
||||
/*** save chages to disk */
|
||||
/*** save changes to disk */
|
||||
public native boolean Save();
|
||||
|
||||
/** override default config value before loading from config file */
|
||||
|
|
|
@ -6,8 +6,11 @@ import android.os.Binder;
|
|||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class LokinetDaemon extends VpnService {
|
||||
|
||||
|
@ -50,13 +53,24 @@ public class LokinetDaemon extends VpnService {
|
|||
int m_FD = -1;
|
||||
int m_UDPSocket = -1;
|
||||
|
||||
private Timer mStatusCheckTimer;
|
||||
private MutableLiveData<Boolean> mStatus = new MutableLiveData<Boolean>();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
mStatus.postValue(false);
|
||||
mStatusCheckTimer = new Timer();
|
||||
mStatusCheckTimer.schedule(new CheckStatus(), 0, 500);
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mStatusCheckTimer != null) {
|
||||
mStatusCheckTimer.cancel();
|
||||
mStatusCheckTimer = null;
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
disconnect();
|
||||
}
|
||||
|
@ -93,12 +107,20 @@ public class LokinetDaemon extends VpnService {
|
|||
// set log leve to info
|
||||
configVals.add(new ConfigValue("logging", "level", "info"));
|
||||
|
||||
boolean connectedSucessfully = connect(configVals);
|
||||
if (connectedSucessfully) return START_STICKY;
|
||||
else return START_NOT_STICKY;
|
||||
boolean connectedSuccessfully = connect(configVals);
|
||||
if (connectedSuccessfully)
|
||||
return START_STICKY;
|
||||
else
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevoke() {
|
||||
mStatus.postValue(false);
|
||||
super.onRevoke();
|
||||
}
|
||||
|
||||
private class ConfigValue {
|
||||
final String Section;
|
||||
final String Key;
|
||||
|
@ -111,8 +133,10 @@ public class LokinetDaemon extends VpnService {
|
|||
}
|
||||
|
||||
public boolean Valid() {
|
||||
if (Section == null || Key == null || Value == null) return false;
|
||||
if (Section.isEmpty() || Key.isEmpty() || Value.isEmpty()) return false;
|
||||
if (Section == null || Key == null || Value == null)
|
||||
return false;
|
||||
if (Section.isEmpty() || Key.isEmpty() || Value.isEmpty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +177,8 @@ public class LokinetDaemon extends VpnService {
|
|||
for (ConfigValue conf : configVals) {
|
||||
if (conf.Valid()) {
|
||||
config.AddDefaultValue(conf.Section, conf.Key, conf.Value);
|
||||
if (conf.Section.equals("dns") && conf.Key.equals("upstream")) upstreamDNS = conf.Value;
|
||||
if (conf.Section.equals("dns") && conf.Key.equals("upstream"))
|
||||
upstreamDNS = conf.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,18 +217,19 @@ public class LokinetDaemon extends VpnService {
|
|||
|
||||
InjectVPNFD();
|
||||
new Thread(
|
||||
() -> {
|
||||
Configure(config);
|
||||
m_UDPSocket = GetUDPSocket();
|
||||
protect(m_UDPSocket);
|
||||
Mainloop();
|
||||
})
|
||||
() -> {
|
||||
Configure(config);
|
||||
m_UDPSocket = GetUDPSocket();
|
||||
protect(m_UDPSocket);
|
||||
Mainloop();
|
||||
})
|
||||
.start();
|
||||
|
||||
Log.d(LOG_TAG, "started successfully!");
|
||||
} else {
|
||||
Log.d(LOG_TAG, "already running");
|
||||
}
|
||||
updateStatus();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -211,15 +237,24 @@ public class LokinetDaemon extends VpnService {
|
|||
if (IsRunning()) {
|
||||
Stop();
|
||||
}
|
||||
// if (impl != null) {
|
||||
// Free(impl);
|
||||
// impl = null;
|
||||
// }
|
||||
// if (impl != null) {
|
||||
// Free(impl);
|
||||
// impl = null;
|
||||
// }
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
private void updateStatus() {
|
||||
mStatus.postValue(IsRunning() && VpnService.prepare(LokinetDaemon.this) == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for clients to access. Because we know this service always runs in the same process as
|
||||
* its clients, we don't need to deal with IPC.
|
||||
* Class for clients to access. Because we know this service always runs in the
|
||||
* same process as its clients, we don't need to deal with IPC.
|
||||
*/
|
||||
public class LocalBinder extends Binder {
|
||||
public LokinetDaemon getService() {
|
||||
|
@ -233,4 +268,10 @@ public class LokinetDaemon extends VpnService {
|
|||
}
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
}
|
||||
|
||||
private class CheckStatus extends TimerTask {
|
||||
public void run() {
|
||||
updateStatus();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,9 +9,11 @@ import android.net.VpnService
|
|||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.lifecycle.Observer
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
|
@ -29,17 +31,40 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
///
|
||||
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
|
||||
/// when the Flutter Engine is detached from the Activity
|
||||
private lateinit var channel: MethodChannel
|
||||
private lateinit var mMethodChannel: MethodChannel
|
||||
private lateinit var mStatusEventChannel: EventChannel
|
||||
private var mEventSink: EventChannel.EventSink? = null
|
||||
|
||||
private var mStatusObserver =
|
||||
Observer<Boolean> { newStatus ->
|
||||
// Propagate to the dart package.
|
||||
mEventSink?.success(newStatus)
|
||||
}
|
||||
|
||||
override fun onAttachedToEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
System.loadLibrary("lokinet-android")
|
||||
|
||||
channel = MethodChannel(binding.binaryMessenger, "lokinet_lib")
|
||||
channel.setMethodCallHandler(this)
|
||||
mMethodChannel = MethodChannel(binding.binaryMessenger, "lokinet_lib_method_channel")
|
||||
mMethodChannel.setMethodCallHandler(this)
|
||||
|
||||
mStatusEventChannel =
|
||||
EventChannel(binding.binaryMessenger, "lokinet_lib_status_event_channel")
|
||||
mStatusEventChannel.setStreamHandler(
|
||||
object : EventChannel.StreamHandler {
|
||||
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
|
||||
mEventSink = events
|
||||
}
|
||||
|
||||
override fun onCancel(arguments: Any?) {
|
||||
mEventSink?.endOfStream()
|
||||
mEventSink = null
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
channel.setMethodCallHandler(null)
|
||||
mMethodChannel.setMethodCallHandler(null)
|
||||
doUnbindService()
|
||||
}
|
||||
|
||||
|
@ -49,15 +74,16 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
|
||||
if (intent != null) {
|
||||
var listener: PluginRegistry.ActivityResultListener? = null
|
||||
listener = PluginRegistry.ActivityResultListener { req, res, _ ->
|
||||
if (req == 0 && res == RESULT_OK) {
|
||||
result.success(true)
|
||||
} else {
|
||||
result.success(false)
|
||||
}
|
||||
listener?.let { activityBinding.removeActivityResultListener(it) }
|
||||
true
|
||||
}
|
||||
listener =
|
||||
PluginRegistry.ActivityResultListener { req, res, _ ->
|
||||
if (req == 0 && res == RESULT_OK) {
|
||||
result.success(true)
|
||||
} else {
|
||||
result.success(false)
|
||||
}
|
||||
listener?.let { activityBinding.removeActivityResultListener(it) }
|
||||
true
|
||||
}
|
||||
activityBinding.addActivityResultListener(listener)
|
||||
activityBinding.activity.startActivityForResult(intent, 0)
|
||||
} else {
|
||||
|
@ -80,7 +106,11 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
val exitNode = call.argument<String>("exit_node")
|
||||
val upstreamDNS = call.argument<String>("upstream_dns")
|
||||
|
||||
val lokinetIntent = Intent(activityBinding.activity.applicationContext, LokinetDaemon::class.java)
|
||||
val lokinetIntent =
|
||||
Intent(
|
||||
activityBinding.activity.applicationContext,
|
||||
LokinetDaemon::class.java
|
||||
)
|
||||
lokinetIntent.action = LokinetDaemon.ACTION_CONNECT
|
||||
lokinetIntent.putExtra(LokinetDaemon.EXIT_NODE, exitNode)
|
||||
lokinetIntent.putExtra(LokinetDaemon.UPSTREAM_DNS, upstreamDNS)
|
||||
|
@ -91,7 +121,11 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
result.success(true)
|
||||
}
|
||||
"disconnect" -> {
|
||||
val lokinetIntent = Intent(activityBinding.activity.applicationContext, LokinetDaemon::class.java)
|
||||
val lokinetIntent =
|
||||
Intent(
|
||||
activityBinding.activity.applicationContext,
|
||||
LokinetDaemon::class.java
|
||||
)
|
||||
lokinetIntent.action = LokinetDaemon.ACTION_DISCONNECT
|
||||
|
||||
activityBinding.activity.applicationContext.startService(lokinetIntent)
|
||||
|
@ -129,26 +163,36 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
|
||||
override fun onDetachedFromActivityForConfigChanges() {}
|
||||
|
||||
private val mConnection: ServiceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||
mBoundService = (service as LokinetDaemon.LocalBinder).getService()
|
||||
}
|
||||
private val mConnection: ServiceConnection =
|
||||
object : ServiceConnection {
|
||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||
mBoundService = (service as LokinetDaemon.LocalBinder).getService()
|
||||
|
||||
override fun onServiceDisconnected(className: ComponentName) {
|
||||
mBoundService = null
|
||||
}
|
||||
}
|
||||
mBoundService?.getStatus()?.observeForever(mStatusObserver)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(className: ComponentName) {
|
||||
mBoundService?.getStatus()?.removeObserver(mStatusObserver)
|
||||
|
||||
mBoundService = null
|
||||
}
|
||||
}
|
||||
|
||||
fun doBindService() {
|
||||
if (activityBinding.activity.applicationContext.bindService(
|
||||
Intent(activityBinding.activity.applicationContext, LokinetDaemon::class.java),
|
||||
mConnection, Context.BIND_AUTO_CREATE
|
||||
)
|
||||
Intent(
|
||||
activityBinding.activity.applicationContext,
|
||||
LokinetDaemon::class.java
|
||||
),
|
||||
mConnection,
|
||||
Context.BIND_AUTO_CREATE
|
||||
)
|
||||
) {
|
||||
mShouldUnbind = true
|
||||
} else {
|
||||
Log.e(
|
||||
LokinetDaemon.LOG_TAG, "Error: The requested service doesn't exist, or this client isn't allowed access to it."
|
||||
LokinetDaemon.LOG_TAG,
|
||||
"Error: The requested service doesn't exist, or this client isn't allowed access to it."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -160,4 +204,3 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,11 @@ import 'package:flutter/services.dart';
|
|||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class LokinetLib {
|
||||
static const MethodChannel _channel = const MethodChannel('lokinet_lib');
|
||||
static const MethodChannel _methodChannel =
|
||||
const MethodChannel('lokinet_lib_method_channel');
|
||||
|
||||
static const EventChannel _statusEventChannel =
|
||||
const EventChannel('lokinet_lib_status_event_channel');
|
||||
|
||||
static Future bootstrapLokinet() async {
|
||||
final request = await HttpClient()
|
||||
|
@ -25,29 +29,29 @@ class LokinetLib {
|
|||
|
||||
static Future<bool> prepareConnection() async {
|
||||
if (!(await isBootstrapped)) await bootstrapLokinet();
|
||||
final bool prepare = await _channel.invokeMethod('prepare');
|
||||
final bool prepare = await _methodChannel.invokeMethod('prepare');
|
||||
return prepare;
|
||||
}
|
||||
|
||||
static Future<bool> connectToLokinet(
|
||||
{String exitNode = "exit.loki", String upstreamDNS = "9.9.9.9"}) async {
|
||||
final bool connect = await _channel.invokeMethod(
|
||||
final bool connect = await _methodChannel.invokeMethod(
|
||||
'connect', {"exit_node": exitNode, "upstream_dns": upstreamDNS});
|
||||
return connect;
|
||||
}
|
||||
|
||||
static Future<bool> disconnectFromLokinet() async {
|
||||
final bool disconnect = await _channel.invokeMethod('disconnect');
|
||||
final bool disconnect = await _methodChannel.invokeMethod('disconnect');
|
||||
return disconnect;
|
||||
}
|
||||
|
||||
static Future<bool> get isPrepared async {
|
||||
final bool prepared = await _channel.invokeMethod('isPrepared');
|
||||
final bool prepared = await _methodChannel.invokeMethod('isPrepared');
|
||||
return prepared;
|
||||
}
|
||||
|
||||
static Future<bool> get isRunning async {
|
||||
final bool isRunning = await _channel.invokeMethod('isRunning');
|
||||
final bool isRunning = await _methodChannel.invokeMethod('isRunning');
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
|
@ -57,8 +61,14 @@ class LokinetLib {
|
|||
}
|
||||
|
||||
static Future<dynamic> get status async {
|
||||
var status = await _channel.invokeMethod('getStatus') as String;
|
||||
var status = await _methodChannel.invokeMethod('getStatus') as String;
|
||||
if (status.isNotEmpty) return jsonDecode(status);
|
||||
return null;
|
||||
}
|
||||
|
||||
static void onStatusUpdate(void Function(bool) onStatusUpdateCallback) {
|
||||
_statusEventChannel
|
||||
.receiveBroadcastStream()
|
||||
.listen((dynamic status) => onStatusUpdateCallback(status));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -204,7 +211,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.3"
|
||||
version: "0.4.8"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
19
pubspec.lock
19
pubspec.lock
|
@ -77,7 +77,7 @@ packages:
|
|||
name: cupertino_icons
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
version: "1.0.4"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -149,6 +149,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -211,7 +218,7 @@ packages:
|
|||
name: platform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.0"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -225,7 +232,7 @@ packages:
|
|||
name: process
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.1"
|
||||
version: "4.2.4"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -314,7 +321,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.3"
|
||||
version: "0.4.8"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -335,7 +342,7 @@ packages:
|
|||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.4.1"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -358,5 +365,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=2.14.0 <3.0.0"
|
||||
dart: ">=2.15.0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
|
Loading…
Reference in New Issue