opt: recent&fav cards

This commit is contained in:
Kingtous 2022-07-22 23:12:31 +08:00
parent fc8fb2d980
commit 5946f6e47d
2 changed files with 158 additions and 34 deletions

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -10,6 +12,12 @@ import '../../mobile/pages/scan_page.dart';
import '../../mobile/pages/settings_page.dart'; import '../../mobile/pages/settings_page.dart';
import '../../models/model.dart'; import '../../models/model.dart';
enum RemoteType {
recently,
favorite,
discovered
}
/// Connection page for connecting to a remote peer. /// Connection page for connecting to a remote peer.
class ConnectionPage extends StatefulWidget implements PageShape { class ConnectionPage extends StatefulWidget implements PageShape {
ConnectionPage({Key? key}) : super(key: key); ConnectionPage({Key? key}) : super(key: key);
@ -62,7 +70,45 @@ class _ConnectionPageState extends State<ConnectionPage> {
).marginOnly(top: 16.0, left: 16.0), ).marginOnly(top: 16.0, left: 16.0),
SizedBox(height: 12), SizedBox(height: 12),
Divider(thickness: 1,), Divider(thickness: 1,),
getPeers(), Expanded(
child: DefaultTabController(
length: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
labelColor: Colors.black87,
isScrollable: true,
indicatorSize: TabBarIndicatorSize.label,
tabs: [
Tab(child: Text(translate("Recent Sessions")),),
Tab(child: Text(translate("Favorites")),),
Tab(child: Text(translate("Discovered")),),
Tab(child: Text(translate("Address Book")),),
]),
Expanded(child: TabBarView(children: [
FutureBuilder<Widget>(future: getPeers(rType: RemoteType.recently),
builder: (context, snapshot){
if (snapshot.hasData) {
return snapshot.data!;
} else {
return Offstage();
}
}),
FutureBuilder<Widget>(future: getPeers(rType: RemoteType.favorite),
builder: (context, snapshot){
if (snapshot.hasData) {
return snapshot.data!;
} else {
return Offstage();
}
}),
Container(),
Container(),
]).paddingSymmetric(horizontal: 12.0,vertical: 4.0))
],
)),
),
]), ]),
); );
} }
@ -230,25 +276,47 @@ class _ConnectionPageState extends State<ConnectionPage> {
if (platform == 'mac os') if (platform == 'mac os')
platform = 'mac'; platform = 'mac';
else if (platform != 'linux' && platform != 'android') platform = 'win'; else if (platform != 'linux' && platform != 'android') platform = 'win';
return Image.asset('assets/$platform.png', width: 24, height: 24); return Image.asset('assets/$platform.png', height: 50);
} }
/// Get all the saved peers. /// Get all the saved peers.
Widget getPeers() { Future<Widget> getPeers({RemoteType rType = RemoteType.recently}) async {
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
final space = 8.0; final space = 8.0;
var width = size.width - 2 * space;
final minWidth = 320.0;
if (size.width > minWidth + 2 * space) {
final n = (size.width / (minWidth + 2 * space)).floor();
width = size.width / n - 2 * space;
}
final cards = <Widget>[]; final cards = <Widget>[];
var peers = gFFI.peers(); var peers;
switch (rType) {
case RemoteType.recently:
peers = gFFI.peers();
break;
case RemoteType.favorite:
peers = await gFFI.bind.mainGetFav().then((peers) async {
final peersEntities = await Future.wait(peers.map((id) => gFFI.bind.mainGetPeers(id: id)).toList(growable: false))
.then((peers_str){
final len = peers_str.length;
final ps = List<Peer>.empty(growable: true);
for(var i = 0; i< len ; i++){
print("${peers[i]}: ${peers_str[i]}");
ps.add(Peer.fromJson(peers[i], jsonDecode(peers_str[i])['info']));
}
return ps;
});
return peersEntities;
});
break;
case RemoteType.discovered:
// TODO: Handle this case.
peers = await gFFI.bind.mainGetLanPeers().then((peers_string){
});
break;
}
peers.forEach((p) { peers.forEach((p) {
cards.add(Container( cards.add(Container(
width: width, width: 250,
height: 150,
child: Card( child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: GestureDetector( child: GestureDetector(
onTap: !isWebDesktop ? () => connect('${p.id}') : null, onTap: !isWebDesktop ? () => connect('${p.id}') : null,
onDoubleTap: isWebDesktop ? () => connect('${p.id}') : null, onDoubleTap: isWebDesktop ? () => connect('${p.id}') : null,
@ -258,18 +326,53 @@ class _ConnectionPageState extends State<ConnectionPage> {
_menuPos = RelativeRect.fromLTRB(x, y, x, y); _menuPos = RelativeRect.fromLTRB(x, y, x, y);
showPeerMenu(context, p.id); showPeerMenu(context, p.id);
}, },
child: ListTile( child: Column(
contentPadding: const EdgeInsets.only(left: 12), mainAxisSize: MainAxisSize.min,
subtitle: Text('${p.username}@${p.hostname}'), mainAxisAlignment: MainAxisAlignment.center,
title: Text('${p.id}'), children: [
leading: Container( Expanded(
child: Container(
decoration: BoxDecoration(
color: str2color('${p.id}${p.platform}', 0x7f),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
)
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
child: getPlatformImage('${p.platform}'), child: getPlatformImage('${p.platform}'),),
color: str2color('${p.id}${p.platform}', 0x7f)), Row(
trailing: InkWell( children: [
child: Padding( Expanded(
padding: const EdgeInsets.all(12), child: Text('${p.username}@${p.hostname}', style: TextStyle(
child: Icon(Icons.more_vert)), color: Colors.white70,
fontSize: 12
),textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
).paddingAll(4.0),
),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("${p.id}"),
InkWell(
child: Icon(Icons.more_vert),
onTapDown: (e) { onTapDown: (e) {
final x = e.globalPosition.dx; final x = e.globalPosition.dx;
final y = e.globalPosition.dy; final y = e.globalPosition.dy;
@ -278,9 +381,12 @@ class _ConnectionPageState extends State<ConnectionPage> {
onTap: () { onTap: () {
showPeerMenu(context, p.id); showPeerMenu(context, p.id);
}), }),
],
).paddingSymmetric(vertical: 8.0,horizontal: 12.0)
],
))))); )))));
}); });
return Wrap(children: cards, spacing: space, runSpacing: space); return SingleChildScrollView(child: Wrap(children: cards, spacing: space, runSpacing: space));
} }
/// Show the peer menu and handle user's choice. /// Show the peer menu and handle user's choice.

View File

@ -20,8 +20,9 @@ use crate::flutter::{self, Session, SESSIONS};
use crate::start_server; use crate::start_server;
use crate::ui_interface; use crate::ui_interface;
use crate::ui_interface::{ use crate::ui_interface::{
change_id, get_app_name, get_async_job_status, get_license, get_options, get_socks, change_id, get_app_name, get_async_job_status, get_fav, get_lan_peers, get_license,
get_sound_inputs, get_version, is_ok_change_id, set_options, set_socks, test_if_valid_server, get_options, get_peer, get_socks, get_sound_inputs, get_version, is_ok_change_id, set_options,
set_socks, store_fav, test_if_valid_server,
}; };
fn initialize(app_dir: &str) { fn initialize(app_dir: &str) {
@ -429,6 +430,23 @@ pub fn main_get_version() -> String {
get_version() get_version()
} }
pub fn main_get_fav() -> Vec<String> {
get_fav()
}
pub fn main_store_fav(favs: Vec<String>) {
store_fav(favs)
}
pub fn main_get_peers(id: String) -> String {
let conf = get_peer(id);
serde_json::to_string(&conf).unwrap_or("".to_string())
}
pub fn main_get_lan_peers() -> String {
get_lan_peers()
}
/// FFI for **get** commands which are idempotent. /// FFI for **get** commands which are idempotent.
/// Return result in c string. /// Return result in c string.
/// ///