mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-13 19:19:09 +08:00
Merge branch 'service' of github.com:open-trade/flutter_hbb into service
This commit is contained in:
commit
72936b55bd
1
android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Symbolic link
1
android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../../../.android/libc++_shared.so
|
1
android/app/src/main/jniLibs/arm64-v8a/libcrypto.so
Symbolic link
1
android/app/src/main/jniLibs/arm64-v8a/libcrypto.so
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../../../.android/libcrypto.so
|
1
android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
Symbolic link
1
android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../../../.android/liblibrustdesk.so
|
1
android/app/src/main/jniLibs/arm64-v8a/libssl.so
Symbolic link
1
android/app/src/main/jniLibs/arm64-v8a/libssl.so
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../../../.android/libssl.so
|
@ -6,7 +6,6 @@ import android.content.Intent
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
||||||
// 开机自启动 此功能暂不开启
|
|
||||||
class BootReceiver : BroadcastReceiver() {
|
class BootReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if ("android.intent.action.BOOT_COMPLETED" == intent.action){
|
if ("android.intent.action.BOOT_COMPLETED" == intent.action){
|
||||||
|
@ -29,7 +29,6 @@ class InputService : AccessibilityService() {
|
|||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
fun rustMouseInput(mask: Int, _x: Int, _y: Int) {
|
fun rustMouseInput(mask: Int, _x: Int, _y: Int) {
|
||||||
|
|
||||||
// TODO 按键抬起按下时候 x y 都是0
|
|
||||||
if (!(mask == 9 || mask == 10)) {
|
if (!(mask == 9 || mask == 10)) {
|
||||||
mouseX = _x * INFO.scale
|
mouseX = _x * INFO.scale
|
||||||
mouseY = _y * INFO.scale
|
mouseY = _y * INFO.scale
|
||||||
@ -77,12 +76,10 @@ class InputService : AccessibilityService() {
|
|||||||
dispatchGesture(builder.build(), object : GestureResultCallback() {
|
dispatchGesture(builder.build(), object : GestureResultCallback() {
|
||||||
override fun onCompleted(gestureDescription: GestureDescription) {
|
override fun onCompleted(gestureDescription: GestureDescription) {
|
||||||
super.onCompleted(gestureDescription)
|
super.onCompleted(gestureDescription)
|
||||||
Log.d(logTag, "滑动成功")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCancelled(gestureDescription: GestureDescription) {
|
override fun onCancelled(gestureDescription: GestureDescription) {
|
||||||
super.onCancelled(gestureDescription)
|
super.onCancelled(gestureDescription)
|
||||||
Log.d(logTag, "滑动失败 ")
|
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
startActivityForResult(mIntent, MEDIA_REQUEST_CODE)
|
startActivityForResult(mIntent, MEDIA_REQUEST_CODE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在onActivityResult中成功获取到mediaProjection就开始就调用此函数,开始初始化监听服务
|
|
||||||
private fun initService() {
|
private fun initService() {
|
||||||
if (mediaProjectionResultIntent == null) {
|
if (mediaProjectionResultIntent == null) {
|
||||||
Log.w(logTag, "initService fail,mediaProjectionResultIntent is null")
|
Log.w(logTag, "initService fail,mediaProjectionResultIntent is null")
|
||||||
@ -178,8 +177,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateMachineInfo() {
|
private fun updateMachineInfo() {
|
||||||
// 屏幕尺寸 控制最长边不超过1400 超过则减半并储存缩放比例 实际发送给手机端的尺寸为缩小后的尺寸
|
|
||||||
// input控制时再通过缩放比例恢复原始尺寸进行path入参
|
|
||||||
val dm = DisplayMetrics()
|
val dm = DisplayMetrics()
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
@ -41,14 +41,14 @@ const val EXTRA_LOGIN_REQ_NOTIFY = "EXTRA_LOGIN_REQ_NOTIFY"
|
|||||||
const val DEFAULT_NOTIFY_TITLE = "RustDesk"
|
const val DEFAULT_NOTIFY_TITLE = "RustDesk"
|
||||||
const val DEFAULT_NOTIFY_TEXT = "Service is running"
|
const val DEFAULT_NOTIFY_TEXT = "Service is running"
|
||||||
const val DEFAULT_NOTIFY_ID = 1
|
const val DEFAULT_NOTIFY_ID = 1
|
||||||
const val NOTIFY_ID_OFFSET = 100 // 为每个客户端ID增加这个偏移量,而得到通知栏ID,避免使用0且防止和默认ID冲突
|
const val NOTIFY_ID_OFFSET = 100
|
||||||
|
|
||||||
const val NOTIFY_TYPE_START_CAPTURE = "NOTIFY_TYPE_START_CAPTURE"
|
const val NOTIFY_TYPE_START_CAPTURE = "NOTIFY_TYPE_START_CAPTURE"
|
||||||
|
|
||||||
const val MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_VP9
|
const val MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_VP9
|
||||||
|
|
||||||
// video const
|
// video const
|
||||||
const val MAX_SCREEN_SIZE = 1200 // 内置编码器有上限 且实际使用中不需要过高的分辨率
|
const val MAX_SCREEN_SIZE = 1200
|
||||||
|
|
||||||
const val VIDEO_KEY_BIT_RATE = 1024_000
|
const val VIDEO_KEY_BIT_RATE = 1024_000
|
||||||
const val VIDEO_KEY_FRAME_RATE = 30
|
const val VIDEO_KEY_FRAME_RATE = 30
|
||||||
@ -157,14 +157,13 @@ class MainService : Service() {
|
|||||||
private val logTag = "LOG_SERVICE"
|
private val logTag = "LOG_SERVICE"
|
||||||
private val useVP9 = false
|
private val useVP9 = false
|
||||||
private val binder = LocalBinder()
|
private val binder = LocalBinder()
|
||||||
private var _isReady = false // 是否获取了录屏权限
|
private var _isReady = false
|
||||||
private var _isStart = false // 是否正在进行录制
|
private var _isStart = false
|
||||||
val isReady: Boolean
|
val isReady: Boolean
|
||||||
get() = _isReady
|
get() = _isReady
|
||||||
val isStart: Boolean
|
val isStart: Boolean
|
||||||
get() = _isStart
|
get() = _isStart
|
||||||
|
|
||||||
// video 注意 这里imageReader要成为成员变量,防止被回收 https://www.cnblogs.com/yongdaimi/p/11004560.html
|
|
||||||
private var mediaProjection: MediaProjection? = null
|
private var mediaProjection: MediaProjection? = null
|
||||||
private var surface: Surface? = null
|
private var surface: Surface? = null
|
||||||
private val sendVP9Thread = Executors.newSingleThreadExecutor()
|
private val sendVP9Thread = Executors.newSingleThreadExecutor()
|
||||||
@ -179,7 +178,7 @@ class MainService : Service() {
|
|||||||
private var audioData: FloatArray? = null
|
private var audioData: FloatArray? = null
|
||||||
private var minBufferSize = 0
|
private var minBufferSize = 0
|
||||||
private var isNewData = false
|
private var isNewData = false
|
||||||
private val audioZeroData: FloatArray = FloatArray(32) // 必须是32位 如果只有8位进行ffi传输时会出错
|
private val audioZeroData: FloatArray = FloatArray(32)
|
||||||
private var audioRecordStat = false
|
private var audioRecordStat = false
|
||||||
|
|
||||||
// notification
|
// notification
|
||||||
@ -208,7 +207,6 @@ class MainService : Service() {
|
|||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
Log.d("whichService", "this service:${Thread.currentThread()}")
|
Log.d("whichService", "this service:${Thread.currentThread()}")
|
||||||
// 只有init的时候通过onStartCommand 且开启前台服务
|
|
||||||
if (intent?.action == INIT_SERVICE) {
|
if (intent?.action == INIT_SERVICE) {
|
||||||
Log.d(logTag, "service starting:${startId}:${Thread.currentThread()}")
|
Log.d(logTag, "service starting:${startId}:${Thread.currentThread()}")
|
||||||
createForegroundNotification()
|
createForegroundNotification()
|
||||||
@ -217,25 +215,20 @@ class MainService : Service() {
|
|||||||
intent.getParcelableExtra<Intent>(EXTRA_MP_DATA)?.let {
|
intent.getParcelableExtra<Intent>(EXTRA_MP_DATA)?.let {
|
||||||
mediaProjection =
|
mediaProjection =
|
||||||
mMediaProjectionManager.getMediaProjection(Activity.RESULT_OK, it)
|
mMediaProjectionManager.getMediaProjection(Activity.RESULT_OK, it)
|
||||||
Log.d(logTag, "获取mMediaProjection成功$mediaProjection")
|
|
||||||
checkMediaPermission()
|
checkMediaPermission()
|
||||||
surface = createSurface()
|
surface = createSurface()
|
||||||
init(this)
|
init(this)
|
||||||
_isReady = true
|
_isReady = true
|
||||||
} ?: let {
|
} ?: let {
|
||||||
Log.d(logTag, "获取mMediaProjection失败!")
|
|
||||||
}
|
}
|
||||||
// } else if (intent?.action == ACTION_LOGIN_REQ_NOTIFY) {
|
// } else if (intent?.action == ACTION_LOGIN_REQ_NOTIFY) {
|
||||||
// 暂时不开启通知从通知栏确认登录
|
|
||||||
// val notifyLoginRes = intent.getBooleanExtra(EXTRA_LOGIN_REQ_NOTIFY, false)
|
// val notifyLoginRes = intent.getBooleanExtra(EXTRA_LOGIN_REQ_NOTIFY, false)
|
||||||
// Log.d(logTag, "从通知栏点击了:$notifyLoginRes")
|
|
||||||
}
|
}
|
||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
private fun createSurface(): Surface? {
|
private fun createSurface(): Surface? {
|
||||||
// 暂时只使用原始数据的情况
|
|
||||||
return if (useVP9) {
|
return if (useVP9) {
|
||||||
// TODO
|
// TODO
|
||||||
null
|
null
|
||||||
@ -246,7 +239,7 @@ class MainService : Service() {
|
|||||||
INFO.screenWidth,
|
INFO.screenWidth,
|
||||||
INFO.screenHeight,
|
INFO.screenHeight,
|
||||||
PixelFormat.RGBA_8888,
|
PixelFormat.RGBA_8888,
|
||||||
2 // maxImages 至少是2
|
2
|
||||||
).apply {
|
).apply {
|
||||||
setOnImageAvailableListener({ imageReader: ImageReader ->
|
setOnImageAvailableListener({ imageReader: ImageReader ->
|
||||||
try {
|
try {
|
||||||
@ -292,7 +285,6 @@ class MainService : Service() {
|
|||||||
startRawVideoRecorder(mediaProjection!!)
|
startRawVideoRecorder(mediaProjection!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 音频只支持安卓10以及以上
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
startAudioRecorder()
|
startAudioRecorder()
|
||||||
}
|
}
|
||||||
@ -363,7 +355,6 @@ class MainService : Service() {
|
|||||||
|
|
||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
private fun startVP9VideoRecorder(mp: MediaProjection) {
|
private fun startVP9VideoRecorder(mp: MediaProjection) {
|
||||||
//使用内置编码器
|
|
||||||
createMediaCodec()
|
createMediaCodec()
|
||||||
videoEncoder?.let {
|
videoEncoder?.let {
|
||||||
surface = it.createInputSurface()
|
surface = it.createInputSurface()
|
||||||
@ -391,7 +382,6 @@ class MainService : Service() {
|
|||||||
) {
|
) {
|
||||||
codec.getOutputBuffer(index)?.let { buf ->
|
codec.getOutputBuffer(index)?.let { buf ->
|
||||||
sendVP9Thread.execute {
|
sendVP9Thread.execute {
|
||||||
// TODO 优化内存使用方式
|
|
||||||
val byteArray = ByteArray(buf.limit())
|
val byteArray = ByteArray(buf.limit())
|
||||||
buf.get(byteArray)
|
buf.get(byteArray)
|
||||||
// sendVp9(byteArray)
|
// sendVp9(byteArray)
|
||||||
@ -411,7 +401,7 @@ class MainService : Service() {
|
|||||||
videoEncoder = MediaCodec.createEncoderByType(MIME_TYPE)
|
videoEncoder = MediaCodec.createEncoderByType(MIME_TYPE)
|
||||||
val mFormat = MediaFormat.createVideoFormat(MIME_TYPE, INFO.screenWidth, INFO.screenHeight)
|
val mFormat = MediaFormat.createVideoFormat(MIME_TYPE, INFO.screenWidth, INFO.screenHeight)
|
||||||
mFormat.setInteger(MediaFormat.KEY_BIT_RATE, VIDEO_KEY_BIT_RATE)
|
mFormat.setInteger(MediaFormat.KEY_BIT_RATE, VIDEO_KEY_BIT_RATE)
|
||||||
mFormat.setInteger(MediaFormat.KEY_FRAME_RATE, VIDEO_KEY_FRAME_RATE) // codec的帧率设置无效
|
mFormat.setInteger(MediaFormat.KEY_FRAME_RATE, VIDEO_KEY_FRAME_RATE)
|
||||||
mFormat.setInteger(
|
mFormat.setInteger(
|
||||||
MediaFormat.KEY_COLOR_FORMAT,
|
MediaFormat.KEY_COLOR_FORMAT,
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible
|
||||||
@ -433,7 +423,6 @@ class MainService : Service() {
|
|||||||
thread {
|
thread {
|
||||||
while (audioRecordStat) {
|
while (audioRecordStat) {
|
||||||
val res = audioRecorder!!.read(audioData!!, 0, minBufferSize, READ_BLOCKING)
|
val res = audioRecorder!!.read(audioData!!, 0, minBufferSize, READ_BLOCKING)
|
||||||
// 录制float 需要使用对应的read float[] 函数
|
|
||||||
if (res != AudioRecord.ERROR_INVALID_OPERATION) {
|
if (res != AudioRecord.ERROR_INVALID_OPERATION) {
|
||||||
isNewData = true
|
isNewData = true
|
||||||
}
|
}
|
||||||
@ -493,7 +482,6 @@ class MainService : Service() {
|
|||||||
|
|
||||||
private fun initNotification() {
|
private fun initNotification() {
|
||||||
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
// 设置通知渠道 android8开始引入 老版本会被忽略 这个东西的作用相当于为通知分类 给用户选择通知消息的种类
|
|
||||||
notificationChannel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
notificationChannel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val channelId = "RustDesk"
|
val channelId = "RustDesk"
|
||||||
val channelName = "RustDesk Service"
|
val channelName = "RustDesk Service"
|
||||||
@ -517,7 +505,7 @@ class MainService : Service() {
|
|||||||
private fun createForegroundNotification() {
|
private fun createForegroundNotification() {
|
||||||
val intent = Intent(this, MainActivity::class.java).apply {
|
val intent = Intent(this, MainActivity::class.java).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
|
||||||
action = Intent.ACTION_MAIN // 不设置会造成每次都重新启动一个新的Activity
|
action = Intent.ACTION_MAIN
|
||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
putExtra("type", type)
|
putExtra("type", type)
|
||||||
}
|
}
|
||||||
@ -539,19 +527,16 @@ class MainService : Service() {
|
|||||||
.setColor(ContextCompat.getColor(this, R.color.primary))
|
.setColor(ContextCompat.getColor(this, R.color.primary))
|
||||||
.setWhen(System.currentTimeMillis())
|
.setWhen(System.currentTimeMillis())
|
||||||
.build()
|
.build()
|
||||||
// 这里满足前台服务首次启动时5s内设定好通知内容,这里使用startForeground,后续普通调用使用notificationManager即可
|
|
||||||
startForeground(DEFAULT_NOTIFY_ID, notification)
|
startForeground(DEFAULT_NOTIFY_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loginRequestNotification(clientID:Int, type: String, username: String, peerId: String) {
|
private fun loginRequestNotification(clientID:Int, type: String, username: String, peerId: String) {
|
||||||
// notificationBuilder 第一次使用时状态已保存,再次生成时只需要调整需要修改的部分
|
|
||||||
cancelNotification(clientID)
|
cancelNotification(clientID)
|
||||||
val notification = notificationBuilder
|
val notification = notificationBuilder
|
||||||
.setOngoing(false)
|
.setOngoing(false)
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
.setContentTitle(translate("Do you accept?"))
|
.setContentTitle(translate("Do you accept?"))
|
||||||
.setContentText("$type:$username-$peerId")
|
.setContentText("$type:$username-$peerId")
|
||||||
// 暂时不开启通知栏接受请求
|
|
||||||
// .setStyle(MediaStyle().setShowActionsInCompactView(0, 1))
|
// .setStyle(MediaStyle().setShowActionsInCompactView(0, 1))
|
||||||
// .addAction(R.drawable.check_blue, "check", genLoginRequestPendingIntent(true))
|
// .addAction(R.drawable.check_blue, "check", genLoginRequestPendingIntent(true))
|
||||||
// .addAction(R.drawable.close_red, "close", genLoginRequestPendingIntent(false))
|
// .addAction(R.drawable.close_red, "close", genLoginRequestPendingIntent(false))
|
||||||
@ -574,11 +559,6 @@ class MainService : Service() {
|
|||||||
return clientID + NOTIFY_ID_OFFSET
|
return clientID + NOTIFY_ID_OFFSET
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭通知的情况
|
|
||||||
* 1.UI端接受或拒绝
|
|
||||||
* 2.peer端通过密码建立了连接(在onClientAuthorizedNotification中已处理) 和 peer端手动取消了连接
|
|
||||||
*/
|
|
||||||
fun cancelNotification(clientID:Int){
|
fun cancelNotification(clientID:Int){
|
||||||
notificationManager.cancel(getClientNotifyID(clientID))
|
notificationManager.cancel(getClientNotifyID(clientID))
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ data class Info(
|
|||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
fun testVP9Support(): Boolean {
|
fun testVP9Support(): Boolean {
|
||||||
return true // 函数内部永远返回true 暂时只使用原始数据
|
return true
|
||||||
val res = MediaCodecList(MediaCodecList.ALL_CODECS)
|
val res = MediaCodecList(MediaCodecList.ALL_CODECS)
|
||||||
.findEncoderForFormat(
|
.findEncoderForFormat(
|
||||||
MediaFormat.createVideoFormat(
|
MediaFormat.createVideoFormat(
|
||||||
|
@ -7,9 +7,6 @@ import 'package:flutter_hbb/pages/chat_page.dart';
|
|||||||
import 'model.dart';
|
import 'model.dart';
|
||||||
|
|
||||||
class ChatModel with ChangeNotifier {
|
class ChatModel with ChangeNotifier {
|
||||||
// -1作为客户端模式的id,客户端模式下此id唯一
|
|
||||||
// 其它正整数的id,来自被控服务器模式下的其他客户端的id,每个客户端有不同的id
|
|
||||||
// 注意 此id和peer_id不同,服务端模式下的id等同于conn的顺序累加id
|
|
||||||
static final clientModeID = -1;
|
static final clientModeID = -1;
|
||||||
|
|
||||||
final Map<int, List<ChatMessage>> _messages = Map()..[clientModeID] = [];
|
final Map<int, List<ChatMessage>> _messages = Map()..[clientModeID] = [];
|
||||||
|
@ -26,10 +26,6 @@ class FileModel extends ChangeNotifier {
|
|||||||
var _localOption = DirectoryOption();
|
var _localOption = DirectoryOption();
|
||||||
var _remoteOption = DirectoryOption();
|
var _remoteOption = DirectoryOption();
|
||||||
|
|
||||||
/// 每一个选择的文件或文件夹占用一个 _jobId,file_num是文件夹中的单独文件id
|
|
||||||
/// 如
|
|
||||||
/// 发送单独一个文件 file_num = 0;
|
|
||||||
/// 发送一个文件夹,若文件夹下有3个文件 最后一个文件的 file_num = 2;
|
|
||||||
var _jobId = 0;
|
var _jobId = 0;
|
||||||
|
|
||||||
var _jobProgress = JobProgress(); // from rust update
|
var _jobProgress = JobProgress(); // from rust update
|
||||||
@ -119,7 +115,6 @@ class FileModel extends ChangeNotifier {
|
|||||||
_fileFetcher.tryCompleteTask(evt['value'], evt['is_local']);
|
_fileFetcher.tryCompleteTask(evt['value'], evt['is_local']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// job 类型 复制结束 删除结束
|
|
||||||
jobDone(Map<String, dynamic> evt) {
|
jobDone(Map<String, dynamic> evt) {
|
||||||
if (_jobResultListener.isListening) {
|
if (_jobResultListener.isListening) {
|
||||||
_jobResultListener.complete(evt);
|
_jobResultListener.complete(evt);
|
||||||
@ -250,7 +245,7 @@ class FileModel extends ChangeNotifier {
|
|||||||
"path": from.path,
|
"path": from.path,
|
||||||
"to": PathUtil.join(toPath, from.name, isWindows),
|
"to": PathUtil.join(toPath, from.name, isWindows),
|
||||||
"show_hidden": showHidden.toString(),
|
"show_hidden": showHidden.toString(),
|
||||||
"is_remote": (!(items.isLocal!)).toString() // 指from的位置而不是to的位置
|
"is_remote": (!(items.isLocal!)).toString()
|
||||||
};
|
};
|
||||||
FFI.setByName("send_files", jsonEncode(msg));
|
FFI.setByName("send_files", jsonEncode(msg));
|
||||||
});
|
});
|
||||||
@ -282,7 +277,6 @@ class FileModel extends ChangeNotifier {
|
|||||||
_jobId, item.path, items.isLocal!, true);
|
_jobId, item.path, items.isLocal!, true);
|
||||||
fd.format(isWindows);
|
fd.format(isWindows);
|
||||||
EasyLoading.dismiss();
|
EasyLoading.dismiss();
|
||||||
// 空文件夹
|
|
||||||
if (fd.entries.isEmpty) {
|
if (fd.entries.isEmpty) {
|
||||||
final confirm = await showRemoveDialog(translate("Are you sure you want to delete this empty directory?"), item.name, false);
|
final confirm = await showRemoveDialog(translate("Are you sure you want to delete this empty directory?"), item.name, false);
|
||||||
if (confirm == true) {
|
if (confirm == true) {
|
||||||
@ -476,7 +470,7 @@ class FileFetcher {
|
|||||||
|
|
||||||
Timer(Duration(seconds: 2), () {
|
Timer(Duration(seconds: 2), () {
|
||||||
tasks.remove(path);
|
tasks.remove(path);
|
||||||
if (c.isCompleted) return; // 计时器加入map
|
if (c.isCompleted) return;
|
||||||
c.completeError("Failed to read dir,timeout");
|
c.completeError("Failed to read dir,timeout");
|
||||||
});
|
});
|
||||||
return c.future;
|
return c.future;
|
||||||
@ -492,7 +486,7 @@ class FileFetcher {
|
|||||||
|
|
||||||
Timer(Duration(seconds: 2), () {
|
Timer(Duration(seconds: 2), () {
|
||||||
tasks.remove(id);
|
tasks.remove(id);
|
||||||
if (c.isCompleted) return; // 计时器加入map
|
if (c.isCompleted) return;
|
||||||
c.completeError("Failed to read dir,timeout");
|
c.completeError("Failed to read dir,timeout");
|
||||||
});
|
});
|
||||||
return c.future;
|
return c.future;
|
||||||
|
@ -419,17 +419,6 @@ showInputWarnAlert() async {
|
|||||||
DialogManager.register(alertContext);
|
DialogManager.register(alertContext);
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(translate("How to get Android input permission?")),
|
title: Text(translate("How to get Android input permission?")),
|
||||||
// content: Text.rich(TextSpan(style: TextStyle(), children: [
|
|
||||||
// // [已安装的服务] : [Installed Services]
|
|
||||||
// // 请在接下来的系统设置页面里,找到并进入[Installed Services]页面,将[RustDesk Input]服务开启。
|
|
||||||
// TextSpan(text: "请在接下来的系统设置页\n进入"),
|
|
||||||
// TextSpan(text: " [服务] ", style: TextStyle(color: MyTheme.accent)),
|
|
||||||
// TextSpan(text: "配置页面\n将"),
|
|
||||||
// TextSpan(
|
|
||||||
// text: " [RustDesk Input] ",
|
|
||||||
// style: TextStyle(color: MyTheme.accent)),
|
|
||||||
// TextSpan(text: "服务开启")
|
|
||||||
// ])),
|
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
@ -83,7 +83,7 @@ class PlatformFFI {
|
|||||||
|
|
||||||
static void setMethodCallHandler(FMethod callback) {}
|
static void setMethodCallHandler(FMethod callback) {}
|
||||||
|
|
||||||
static Future<bool> invokeMethod(String method) async {
|
static Future<bool> invokeMethod(String method, [ dynamic arguments]) async {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class ChatPage extends StatelessWidget implements PageShape {
|
|||||||
@override
|
@override
|
||||||
final appBarActions = [
|
final appBarActions = [
|
||||||
PopupMenuButton<int>(
|
PopupMenuButton<int>(
|
||||||
icon: Icon(Icons.list_alt),
|
icon: Icon(Icons.more_vert),
|
||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
final chatModel = FFI.chatModel;
|
final chatModel = FFI.chatModel;
|
||||||
final serverModel = FFI.serverModel;
|
final serverModel = FFI.serverModel;
|
||||||
@ -194,9 +194,7 @@ class _ChatWindowOverlayState extends State<ChatWindowOverlay> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
checkScreenSize() {
|
checkScreenSize() {}
|
||||||
// TODO 横屏处理
|
|
||||||
}
|
|
||||||
|
|
||||||
checkKeyboard() {
|
checkKeyboard() {
|
||||||
final bottomHeight = MediaQuery.of(context).viewInsets.bottom;
|
final bottomHeight = MediaQuery.of(context).viewInsets.bottom;
|
||||||
|
@ -286,37 +286,40 @@ class _WebMenuState extends State<WebMenu> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Provider.of<FfiModel>(context);
|
Provider.of<FfiModel>(context);
|
||||||
final username = getUsername();
|
final username = getUsername();
|
||||||
return PopupMenuButton<String>(itemBuilder: (context) {
|
return PopupMenuButton<String>(
|
||||||
return [
|
icon: Icon(Icons.more_vert),
|
||||||
PopupMenuItem(
|
itemBuilder: (context) {
|
||||||
child: Text(translate('ID/Relay Server')),
|
return [
|
||||||
value: "server",
|
PopupMenuItem(
|
||||||
),
|
child: Text(translate('ID/Relay Server')),
|
||||||
PopupMenuItem(
|
value: "server",
|
||||||
child: Text(username == null
|
),
|
||||||
? translate("Login")
|
PopupMenuItem(
|
||||||
: translate("Logout") + ' ($username)'),
|
child: Text(username == null
|
||||||
value: "login",
|
? translate("Login")
|
||||||
),
|
: translate("Logout") + ' ($username)'),
|
||||||
PopupMenuItem(
|
value: "login",
|
||||||
child: Text(translate('About') + ' RustDesk'),
|
),
|
||||||
value: "about",
|
PopupMenuItem(
|
||||||
)
|
child: Text(translate('About') + ' RustDesk'),
|
||||||
];
|
value: "about",
|
||||||
}, onSelected: (value) {
|
)
|
||||||
if (value == 'server') {
|
];
|
||||||
showServer();
|
},
|
||||||
}
|
onSelected: (value) {
|
||||||
if (value == 'about') {
|
if (value == 'server') {
|
||||||
showAbout();
|
showServer();
|
||||||
}
|
}
|
||||||
if (value == 'login') {
|
if (value == 'about') {
|
||||||
if (username == null) {
|
showAbout();
|
||||||
showLogin();
|
}
|
||||||
} else {
|
if (value == 'login') {
|
||||||
logout();
|
if (username == null) {
|
||||||
}
|
showLogin();
|
||||||
}
|
} else {
|
||||||
});
|
logout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,6 @@ class _FileManagerPageState extends State<FileManagerPage> {
|
|||||||
|
|
||||||
if (model.selectMode) {
|
if (model.selectMode) {
|
||||||
if (_selectedItems.length == 0 || !isOtherPage) {
|
if (_selectedItems.length == 0 || !isOtherPage) {
|
||||||
// 选择模式 当前选择页面
|
|
||||||
return BottomSheetBody(
|
return BottomSheetBody(
|
||||||
leading: Icon(Icons.check),
|
leading: Icon(Icons.check),
|
||||||
title: translate("Selected"),
|
title: translate("Selected"),
|
||||||
@ -377,7 +376,6 @@ class _FileManagerPageState extends State<FileManagerPage> {
|
|||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// 选择模式 复制目标页面
|
|
||||||
return BottomSheetBody(
|
return BottomSheetBody(
|
||||||
leading: Icon(Icons.input),
|
leading: Icon(Icons.input),
|
||||||
title: translate("Paste here?"),
|
title: translate("Paste here?"),
|
||||||
|
@ -17,41 +17,44 @@ class ServerPage extends StatelessWidget implements PageShape {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
final appBarActions = [
|
final appBarActions = [
|
||||||
PopupMenuButton<String>(itemBuilder: (context) {
|
PopupMenuButton<String>(
|
||||||
return [
|
icon: Icon(Icons.more_vert),
|
||||||
PopupMenuItem(
|
itemBuilder: (context) {
|
||||||
child: Text(translate("Change ID")),
|
return [
|
||||||
value: "changeID",
|
PopupMenuItem(
|
||||||
enabled: false,
|
child: Text(translate("Change ID")),
|
||||||
),
|
value: "changeID",
|
||||||
PopupMenuItem(
|
enabled: false,
|
||||||
child: Text(translate("Set your own password")),
|
),
|
||||||
value: "changePW",
|
PopupMenuItem(
|
||||||
enabled: FFI.serverModel.isStart,
|
child: Text(translate("Set your own password")),
|
||||||
),
|
value: "changePW",
|
||||||
PopupMenuItem(
|
enabled: FFI.serverModel.isStart,
|
||||||
child: Text(translate("Refresh random password")),
|
),
|
||||||
value: "refreshPW",
|
PopupMenuItem(
|
||||||
enabled: FFI.serverModel.isStart,
|
child: Text(translate("Refresh random password")),
|
||||||
)
|
value: "refreshPW",
|
||||||
];
|
enabled: FFI.serverModel.isStart,
|
||||||
}, onSelected: (value) {
|
)
|
||||||
if (value == "changeID") {
|
];
|
||||||
// TODO
|
},
|
||||||
} else if (value == "changePW") {
|
onSelected: (value) {
|
||||||
updatePasswordDialog();
|
if (value == "changeID") {
|
||||||
} else if (value == "refreshPW") {
|
// TODO
|
||||||
() async {
|
} else if (value == "changePW") {
|
||||||
showLoading(translate("Waiting"));
|
updatePasswordDialog();
|
||||||
if(await FFI.serverModel.updatePassword("")){
|
} else if (value == "refreshPW") {
|
||||||
showSuccess();
|
() async {
|
||||||
}else{
|
showLoading(translate("Waiting"));
|
||||||
showError();
|
if (await FFI.serverModel.updatePassword("")) {
|
||||||
|
showSuccess();
|
||||||
|
} else {
|
||||||
|
showError();
|
||||||
|
}
|
||||||
|
debugPrint("end updatePassword");
|
||||||
|
}();
|
||||||
}
|
}
|
||||||
debugPrint("end updatePassword");
|
})
|
||||||
}();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -239,8 +239,8 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
|
|
||||||
bool _isStart = false;
|
bool _isStart = false;
|
||||||
|
|
||||||
Timer? _firstTapUpTimer; // 第一次点击后的计时 超时未等到第二次操作则reject
|
Timer? _firstTapUpTimer;
|
||||||
Timer? _secondTapDownTimer; // 第二次点击后的计时 期间内有其他的操作则reject 超时则判定成功 drag update
|
Timer? _secondTapDownTimer;
|
||||||
_TapTracker? _firstTap;
|
_TapTracker? _firstTap;
|
||||||
_TapTracker? _secondTap;
|
_TapTracker? _secondTap;
|
||||||
|
|
||||||
@ -266,7 +266,6 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void addAllowedPointer(PointerDownEvent event) {
|
void addAllowedPointer(PointerDownEvent event) {
|
||||||
// 检测按下事件
|
|
||||||
if (_firstTap != null) {
|
if (_firstTap != null) {
|
||||||
if (!_firstTap!.isWithinGlobalTolerance(event, kDoubleTapSlop)) {
|
if (!_firstTap!.isWithinGlobalTolerance(event, kDoubleTapSlop)) {
|
||||||
// Ignore out-of-bounds second taps.
|
// Ignore out-of-bounds second taps.
|
||||||
@ -285,7 +284,7 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
localPosition: event.localPosition)));
|
localPosition: event.localPosition)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_trackTap(event); // 捕捉第一次tap
|
_trackTap(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _trackTap(PointerDownEvent event) {
|
void _trackTap(PointerDownEvent event) {
|
||||||
@ -301,14 +300,12 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
tracker.startTrackingPointer(_handleEvent, event.transform);
|
tracker.startTrackingPointer(_handleEvent, event.transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 实际的逻辑应该是第二次down后一段时间没有抬起则表示start 刚好是双击取反
|
|
||||||
void _handleEvent(PointerEvent event) {
|
void _handleEvent(PointerEvent event) {
|
||||||
final _TapTracker tracker = _trackers[event.pointer]!;
|
final _TapTracker tracker = _trackers[event.pointer]!;
|
||||||
if (event is PointerUpEvent) {
|
if (event is PointerUpEvent) {
|
||||||
if (_firstTap == null && _secondTap == null) {
|
if (_firstTap == null && _secondTap == null) {
|
||||||
_registerFirstTap(tracker);
|
_registerFirstTap(tracker);
|
||||||
} else {
|
} else {
|
||||||
// 检测到其他的抬起事件则取消
|
|
||||||
_reject(tracker);
|
_reject(tracker);
|
||||||
}
|
}
|
||||||
} else if (event is PointerDownEvent) {
|
} else if (event is PointerDownEvent) {
|
||||||
@ -316,7 +313,6 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
_registerSecondTap(tracker);
|
_registerSecondTap(tracker);
|
||||||
}
|
}
|
||||||
} else if (event is PointerMoveEvent) {
|
} else if (event is PointerMoveEvent) {
|
||||||
// 检测到first tap move 则取消,检测到second tap move且已经通过竞技场则update
|
|
||||||
if (!tracker.isWithinGlobalTolerance(event, kDoubleTapTouchSlop)) {
|
if (!tracker.isWithinGlobalTolerance(event, kDoubleTapTouchSlop)) {
|
||||||
if (_firstTap != null && _firstTap!.pointer == event.pointer) {
|
if (_firstTap != null && _firstTap!.pointer == event.pointer) {
|
||||||
// first tap move
|
// first tap move
|
||||||
@ -403,7 +399,6 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
GestureBinding.instance!.gestureArena.release(tracker.pointer);
|
GestureBinding.instance!.gestureArena.release(tracker.pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO 正确的释放资源
|
|
||||||
_firstTap = null;
|
_firstTap = null;
|
||||||
_secondTap = null;
|
_secondTap = null;
|
||||||
_clearTrackers();
|
_clearTrackers();
|
||||||
@ -420,7 +415,6 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _registerSecondTap(_TapTracker tracker) {
|
void _registerSecondTap(_TapTracker tracker) {
|
||||||
// 清除first tap的状态
|
|
||||||
if (_firstTap != null) {
|
if (_firstTap != null) {
|
||||||
_stopFirstTapUpTimer();
|
_stopFirstTapUpTimer();
|
||||||
_freezeTracker(_firstTap!);
|
_freezeTracker(_firstTap!);
|
||||||
@ -489,7 +483,7 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
|||||||
GestureTapDownCallback? onDoubleFinerTap;
|
GestureTapDownCallback? onDoubleFinerTap;
|
||||||
GestureTapCancelCallback? onDoubleFinerTapCancel;
|
GestureTapCancelCallback? onDoubleFinerTapCancel;
|
||||||
|
|
||||||
Timer? _firstTapTimer; // 第一次点击后的计时 超时未等到第二次操作则reject
|
Timer? _firstTapTimer;
|
||||||
_TapTracker? _firstTap;
|
_TapTracker? _firstTap;
|
||||||
|
|
||||||
var _isStart = false;
|
var _isStart = false;
|
||||||
@ -518,7 +512,6 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void addAllowedPointer(PointerDownEvent event) {
|
void addAllowedPointer(PointerDownEvent event) {
|
||||||
// 检测按下事件
|
|
||||||
debugPrint("addAllowedPointer");
|
debugPrint("addAllowedPointer");
|
||||||
if (_isStart) {
|
if (_isStart) {
|
||||||
// second
|
// second
|
||||||
@ -536,7 +529,7 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
|||||||
_isStart = true;
|
_isStart = true;
|
||||||
_startFirstTapDownTimer();
|
_startFirstTapDownTimer();
|
||||||
}
|
}
|
||||||
_trackTap(event); // 捕捉tap
|
_trackTap(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _trackTap(PointerDownEvent event) {
|
void _trackTap(PointerDownEvent event) {
|
||||||
@ -553,7 +546,6 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
|||||||
_registerTap(tracker);
|
_registerTap(tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 实际的逻辑应该是第二次down后一段时间没有抬起则表示start 刚好是双击取反
|
|
||||||
void _handleEvent(PointerEvent event) {
|
void _handleEvent(PointerEvent event) {
|
||||||
final _TapTracker tracker = _trackers[event.pointer]!;
|
final _TapTracker tracker = _trackers[event.pointer]!;
|
||||||
if (event is PointerUpEvent) {
|
if (event is PointerUpEvent) {
|
||||||
@ -608,7 +600,6 @@ class DoubleFinerTapGestureRecognizer extends GestureRecognizer {
|
|||||||
void _reset() {
|
void _reset() {
|
||||||
_stopFirstTapUpTimer();
|
_stopFirstTapUpTimer();
|
||||||
_firstTap = null;
|
_firstTap = null;
|
||||||
// TODO 正确的释放资源
|
|
||||||
_clearTrackers();
|
_clearTrackers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user