Merge pull request #1247 from Heap-Hop/flutter_desktop
Update desktop and mobile chat message
This commit is contained in:
commit
0529e33434
@ -115,11 +115,6 @@ class _RemotePageState extends State<RemotePage>
|
||||
if (v < 100) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
overlays: []);
|
||||
// [pi.version.isNotEmpty] -> check ready or not,avoid login without soft-keyboard
|
||||
if (chatWindowOverlayEntry == null &&
|
||||
_ffi.ffiModel.pi.version.isNotEmpty) {
|
||||
_ffi.invokeMethod("enable_soft_keyboard", false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -266,9 +261,10 @@ class _RemotePageState extends State<RemotePage>
|
||||
body: Overlay(
|
||||
initialEntries: [
|
||||
OverlayEntry(builder: (context) {
|
||||
_ffi.chatModel.setOverlayState(Overlay.of(context));
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
child: getBodyForDesktopWithListener(keyboard));
|
||||
child: getRawPointerAndKeyBody(getBodyForDesktop(keyboard)));
|
||||
})
|
||||
],
|
||||
));
|
||||
@ -290,8 +286,8 @@ class _RemotePageState extends State<RemotePage>
|
||||
ChangeNotifierProvider.value(value: _ffi.cursorModel),
|
||||
ChangeNotifierProvider.value(value: _ffi.canvasModel),
|
||||
],
|
||||
child: getRawPointerAndKeyBody(Consumer<FfiModel>(
|
||||
builder: (context, ffiModel, _child) => buildBody(ffiModel)))));
|
||||
child: Consumer<FfiModel>(
|
||||
builder: (context, ffiModel, _child) => buildBody(ffiModel))));
|
||||
}
|
||||
|
||||
Widget getRawPointerAndKeyBody(Widget child) {
|
||||
@ -467,7 +463,7 @@ class _RemotePageState extends State<RemotePage>
|
||||
onPressed: () {
|
||||
_ffi.chatModel
|
||||
.changeCurrentID(ChatModel.clientModeID);
|
||||
toggleChatOverlay();
|
||||
_ffi.chatModel.toggleChatOverlay();
|
||||
},
|
||||
)
|
||||
]) +
|
||||
@ -502,11 +498,27 @@ class _RemotePageState extends State<RemotePage>
|
||||
/// DoubleFiner -> right click
|
||||
/// HoldDrag -> left drag
|
||||
|
||||
Widget getBodyForDesktopWithListener(bool keyboard) {
|
||||
Widget getBodyForDesktop(bool keyboard) {
|
||||
var paints = <Widget>[
|
||||
ImagePaint(
|
||||
id: widget.id,
|
||||
)
|
||||
MouseRegion(
|
||||
onEnter: (evt) {
|
||||
bind.hostStopSystemKeyPropagate(stopped: false);
|
||||
},
|
||||
onExit: (evt) {
|
||||
bind.hostStopSystemKeyPropagate(stopped: true);
|
||||
},
|
||||
child: Container(
|
||||
color: MyTheme.canvasColor,
|
||||
child: LayoutBuilder(builder: (context, constraints) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
Provider.of<CanvasModel>(context, listen: false)
|
||||
.updateViewStyle();
|
||||
});
|
||||
return ImagePaint(
|
||||
id: widget.id,
|
||||
);
|
||||
}),
|
||||
))
|
||||
];
|
||||
final cursor = bind.getSessionToggleOptionSync(
|
||||
id: widget.id, arg: 'show-remote-cursor');
|
||||
@ -516,26 +528,9 @@ class _RemotePageState extends State<RemotePage>
|
||||
));
|
||||
}
|
||||
paints.add(getHelpTools());
|
||||
|
||||
return MouseRegion(
|
||||
onEnter: (evt) {
|
||||
bind.hostStopSystemKeyPropagate(stopped: false);
|
||||
},
|
||||
onExit: (evt) {
|
||||
bind.hostStopSystemKeyPropagate(stopped: true);
|
||||
},
|
||||
child: Container(
|
||||
color: MyTheme.canvasColor,
|
||||
child: LayoutBuilder(builder: (context, constraints) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
Provider.of<CanvasModel>(context, listen: false)
|
||||
.updateViewStyle();
|
||||
});
|
||||
return Stack(
|
||||
children: paints,
|
||||
);
|
||||
}),
|
||||
));
|
||||
return Stack(
|
||||
children: paints,
|
||||
);
|
||||
}
|
||||
|
||||
int lastMouseDownButtons = 0;
|
||||
|
@ -4,10 +4,15 @@ import 'package:flutter_hbb/common.dart';
|
||||
import 'package:flutter_hbb/models/chat_model.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../models/model.dart';
|
||||
import 'home_page.dart';
|
||||
|
||||
class ChatPage extends StatelessWidget implements PageShape {
|
||||
late final ChatModel chatModel;
|
||||
|
||||
ChatPage({ChatModel? chatModel}) {
|
||||
this.chatModel = chatModel ?? gFFI.chatModel;
|
||||
}
|
||||
|
||||
@override
|
||||
final title = translate("Chat");
|
||||
|
||||
@ -19,6 +24,7 @@ class ChatPage extends StatelessWidget implements PageShape {
|
||||
PopupMenuButton<int>(
|
||||
icon: Icon(Icons.group),
|
||||
itemBuilder: (context) {
|
||||
// only mobile need [appBarActions], just bind gFFI.chatModel
|
||||
final chatModel = gFFI.chatModel;
|
||||
return chatModel.messages.entries.map((entry) {
|
||||
final id = entry.key;
|
||||
@ -37,7 +43,7 @@ class ChatPage extends StatelessWidget implements PageShape {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider.value(
|
||||
value: gFFI.chatModel,
|
||||
value: chatModel,
|
||||
child: Container(
|
||||
color: MyTheme.grayBg,
|
||||
child: Consumer<ChatModel>(builder: (context, chatModel, child) {
|
||||
|
@ -3,7 +3,6 @@ import 'package:flutter_hbb/mobile/pages/chat_page.dart';
|
||||
import 'package:flutter_hbb/mobile/pages/server_page.dart';
|
||||
import 'package:flutter_hbb/mobile/pages/settings_page.dart';
|
||||
import '../../common.dart';
|
||||
import '../widgets/overlay.dart';
|
||||
import 'connection_page.dart';
|
||||
|
||||
abstract class PageShape extends Widget {
|
||||
@ -79,8 +78,8 @@ class _HomePageState extends State<HomePage> {
|
||||
onTap: (index) => setState(() {
|
||||
// close chat overlay when go chat page
|
||||
if (index == 1 && _selectedIndex != index) {
|
||||
hideChatIconOverlay();
|
||||
hideChatWindowOverlay();
|
||||
gFFI.chatModel.hideChatIconOverlay();
|
||||
gFFI.chatModel.hideChatWindowOverlay();
|
||||
}
|
||||
_selectedIndex = index;
|
||||
}),
|
||||
|
@ -96,8 +96,8 @@ class _RemotePageState extends State<RemotePage> {
|
||||
if (v < 100) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
overlays: []);
|
||||
// [pi.version.isNotEmpty] -> check ready or not,avoid login without soft-keyboard
|
||||
if (chatWindowOverlayEntry == null &&
|
||||
// [pi.version.isNotEmpty] -> check ready or not, avoid login without soft-keyboard
|
||||
if (gFFI.chatModel.chatWindowOverlayEntry == null &&
|
||||
gFFI.ffiModel.pi.version.isNotEmpty) {
|
||||
gFFI.invokeMethod("enable_soft_keyboard", false);
|
||||
}
|
||||
@ -453,7 +453,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
onPressed: () {
|
||||
gFFI.chatModel
|
||||
.changeCurrentID(ChatModel.clientModeID);
|
||||
toggleChatOverlay();
|
||||
gFFI.chatModel.toggleChatOverlay();
|
||||
},
|
||||
)
|
||||
]) +
|
||||
|
@ -1,22 +1,23 @@
|
||||
import 'package:draggable_float_widget/draggable_float_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
|
||||
import '../../models/chat_model.dart';
|
||||
import '../../models/model.dart';
|
||||
import '../pages/chat_page.dart';
|
||||
|
||||
OverlayEntry? chatIconOverlayEntry;
|
||||
OverlayEntry? chatWindowOverlayEntry;
|
||||
|
||||
OverlayEntry? mobileActionsOverlayEntry;
|
||||
|
||||
class DraggableChatWindow extends StatelessWidget {
|
||||
DraggableChatWindow(
|
||||
{this.position = Offset.zero, required this.width, required this.height});
|
||||
{this.position = Offset.zero,
|
||||
required this.width,
|
||||
required this.height,
|
||||
required this.chatModel});
|
||||
|
||||
final Offset position;
|
||||
final double width;
|
||||
final double height;
|
||||
final ChatModel chatModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -27,7 +28,7 @@ class DraggableChatWindow extends StatelessWidget {
|
||||
height: height,
|
||||
builder: (_, onPanUpdate) {
|
||||
return isIOS
|
||||
? ChatPage()
|
||||
? ChatPage(chatModel: chatModel)
|
||||
: Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: CustomAppBar(
|
||||
@ -53,13 +54,13 @@ class DraggableChatWindow extends StatelessWidget {
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
hideChatWindowOverlay();
|
||||
chatModel.hideChatWindowOverlay();
|
||||
},
|
||||
icon: Icon(Icons.keyboard_arrow_down)),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
hideChatWindowOverlay();
|
||||
hideChatIconOverlay();
|
||||
chatModel.hideChatWindowOverlay();
|
||||
chatModel.hideChatIconOverlay();
|
||||
},
|
||||
icon: Icon(Icons.close))
|
||||
],
|
||||
@ -68,7 +69,7 @@ class DraggableChatWindow extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
body: ChatPage(),
|
||||
body: ChatPage(chatModel: chatModel),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -91,81 +92,6 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
Size get preferredSize => new Size.fromHeight(kToolbarHeight);
|
||||
}
|
||||
|
||||
showChatIconOverlay({Offset offset = const Offset(200, 50)}) {
|
||||
if (chatIconOverlayEntry != null) {
|
||||
chatIconOverlayEntry!.remove();
|
||||
}
|
||||
if (globalKey.currentState == null || globalKey.currentState!.overlay == null)
|
||||
return;
|
||||
final bar = navigationBarKey.currentWidget;
|
||||
if (bar != null) {
|
||||
if ((bar as BottomNavigationBar).currentIndex == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final globalOverlayState = globalKey.currentState!.overlay!;
|
||||
|
||||
final overlay = OverlayEntry(builder: (context) {
|
||||
return DraggableFloatWidget(
|
||||
config: DraggableFloatWidgetBaseConfig(
|
||||
initPositionYInTop: false,
|
||||
initPositionYMarginBorder: 100,
|
||||
borderTopContainTopBar: true,
|
||||
),
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
if (chatWindowOverlayEntry == null) {
|
||||
showChatWindowOverlay();
|
||||
} else {
|
||||
hideChatWindowOverlay();
|
||||
}
|
||||
},
|
||||
child: Icon(Icons.message)));
|
||||
});
|
||||
globalOverlayState.insert(overlay);
|
||||
chatIconOverlayEntry = overlay;
|
||||
}
|
||||
|
||||
hideChatIconOverlay() {
|
||||
if (chatIconOverlayEntry != null) {
|
||||
chatIconOverlayEntry!.remove();
|
||||
chatIconOverlayEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
showChatWindowOverlay() {
|
||||
if (chatWindowOverlayEntry != null) return;
|
||||
if (globalKey.currentState == null || globalKey.currentState!.overlay == null)
|
||||
return;
|
||||
final globalOverlayState = globalKey.currentState!.overlay!;
|
||||
|
||||
final overlay = OverlayEntry(builder: (context) {
|
||||
return DraggableChatWindow(
|
||||
position: Offset(20, 80), width: 250, height: 350);
|
||||
});
|
||||
globalOverlayState.insert(overlay);
|
||||
chatWindowOverlayEntry = overlay;
|
||||
}
|
||||
|
||||
hideChatWindowOverlay() {
|
||||
if (chatWindowOverlayEntry != null) {
|
||||
chatWindowOverlayEntry!.remove();
|
||||
chatWindowOverlayEntry = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
toggleChatOverlay() {
|
||||
if (chatIconOverlayEntry == null || chatWindowOverlayEntry == null) {
|
||||
gFFI.invokeMethod("enable_soft_keyboard", true);
|
||||
showChatIconOverlay();
|
||||
showChatWindowOverlay();
|
||||
} else {
|
||||
hideChatIconOverlay();
|
||||
hideChatWindowOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
/// floating buttons of back/home/recent actions for android
|
||||
class DraggableMobileActions extends StatelessWidget {
|
||||
DraggableMobileActions(
|
||||
|
@ -1,8 +1,10 @@
|
||||
import 'package:dash_chat_2/dash_chat_2.dart';
|
||||
import 'package:draggable_float_widget/draggable_float_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
|
||||
import '../../mobile/widgets/overlay.dart';
|
||||
import '../common.dart';
|
||||
import 'model.dart';
|
||||
|
||||
class MessageBody {
|
||||
@ -22,6 +24,14 @@ class MessageBody {
|
||||
class ChatModel with ChangeNotifier {
|
||||
static final clientModeID = -1;
|
||||
|
||||
/// _overlayState:
|
||||
/// Desktop: store session overlay by using [setOverlayState].
|
||||
/// Mobile: always null, use global overlay.
|
||||
/// see [_getOverlayState] in [showChatIconOverlay] or [showChatWindowOverlay]
|
||||
OverlayState? _overlayState;
|
||||
OverlayEntry? chatIconOverlayEntry;
|
||||
OverlayEntry? chatWindowOverlayEntry;
|
||||
|
||||
final ChatUser me = ChatUser(
|
||||
id: "",
|
||||
firstName: "Me",
|
||||
@ -51,6 +61,94 @@ class ChatModel with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
setOverlayState(OverlayState? os) {
|
||||
_overlayState = os;
|
||||
}
|
||||
|
||||
OverlayState? _getOverlayState() {
|
||||
if (_overlayState == null) {
|
||||
if (globalKey.currentState == null ||
|
||||
globalKey.currentState!.overlay == null) return null;
|
||||
return globalKey.currentState!.overlay;
|
||||
} else {
|
||||
return _overlayState;
|
||||
}
|
||||
}
|
||||
|
||||
showChatIconOverlay({Offset offset = const Offset(200, 50)}) {
|
||||
if (chatIconOverlayEntry != null) {
|
||||
chatIconOverlayEntry!.remove();
|
||||
}
|
||||
// mobile check navigationBar
|
||||
final bar = navigationBarKey.currentWidget;
|
||||
if (bar != null) {
|
||||
if ((bar as BottomNavigationBar).currentIndex == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final overlayState = _getOverlayState();
|
||||
if (overlayState == null) return;
|
||||
|
||||
final overlay = OverlayEntry(builder: (context) {
|
||||
return DraggableFloatWidget(
|
||||
config: DraggableFloatWidgetBaseConfig(
|
||||
initPositionYInTop: false,
|
||||
initPositionYMarginBorder: 100,
|
||||
borderTopContainTopBar: true,
|
||||
),
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
if (chatWindowOverlayEntry == null) {
|
||||
showChatWindowOverlay();
|
||||
} else {
|
||||
hideChatWindowOverlay();
|
||||
}
|
||||
},
|
||||
child: Icon(Icons.message)));
|
||||
});
|
||||
overlayState.insert(overlay);
|
||||
chatIconOverlayEntry = overlay;
|
||||
}
|
||||
|
||||
hideChatIconOverlay() {
|
||||
if (chatIconOverlayEntry != null) {
|
||||
chatIconOverlayEntry!.remove();
|
||||
chatIconOverlayEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
showChatWindowOverlay() {
|
||||
if (chatWindowOverlayEntry != null) return;
|
||||
final overlayState = _getOverlayState();
|
||||
if (overlayState == null) return;
|
||||
final overlay = OverlayEntry(builder: (context) {
|
||||
return DraggableChatWindow(
|
||||
position: Offset(20, 80), width: 250, height: 350, chatModel: this);
|
||||
});
|
||||
overlayState.insert(overlay);
|
||||
chatWindowOverlayEntry = overlay;
|
||||
}
|
||||
|
||||
hideChatWindowOverlay() {
|
||||
if (chatWindowOverlayEntry != null) {
|
||||
chatWindowOverlayEntry!.remove();
|
||||
chatWindowOverlayEntry = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
toggleChatOverlay() {
|
||||
if (chatIconOverlayEntry == null || chatWindowOverlayEntry == null) {
|
||||
gFFI.invokeMethod("enable_soft_keyboard", true);
|
||||
showChatIconOverlay();
|
||||
showChatWindowOverlay();
|
||||
} else {
|
||||
hideChatIconOverlay();
|
||||
hideChatWindowOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
changeCurrentID(int id) {
|
||||
if (_messages.containsKey(id)) {
|
||||
_currentID = id;
|
||||
@ -117,6 +215,7 @@ class ChatModel with ChangeNotifier {
|
||||
close() {
|
||||
hideChatIconOverlay();
|
||||
hideChatWindowOverlay();
|
||||
_overlayState = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user