mirror of
https://github.com/amigan/calls.git
synced 2025-01-31 05:22:37 -05:00
big huge wip
This commit is contained in:
parent
db99eeb43a
commit
0d150d73d8
10 changed files with 135 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:web_socket_channel/io.dart';
|
import 'package:web_socket_channel/io.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import '../pb/stillbox.pb.dart';
|
import '../pb/stillbox.pb.dart';
|
||||||
import 'play.dart';
|
import 'play.dart';
|
||||||
|
@ -16,6 +17,7 @@ class Stillbox extends ChangeNotifier {
|
||||||
Filter? currentFilter;
|
Filter? currentFilter;
|
||||||
Call? _currentCall;
|
Call? _currentCall;
|
||||||
Map<String, String> headers = {};
|
Map<String, String> headers = {};
|
||||||
|
Uri? baseUri = Uri.base;
|
||||||
|
|
||||||
set state(LiveState newState) {
|
set state(LiveState newState) {
|
||||||
channel.sink.add(Live(state: newState, filter: currentFilter));
|
channel.sink.add(Live(state: newState, filter: currentFilter));
|
||||||
|
@ -34,18 +36,56 @@ class Stillbox extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stillbox() {
|
Stillbox() {
|
||||||
String socketUrl = 'ws://xenon:3050/ws';
|
setUris();
|
||||||
Uri baseUri = Uri.base;
|
|
||||||
if (baseUri.scheme == 'http' || baseUri.scheme == 'https') {
|
|
||||||
final port = (baseUri.hasPort ? ':${baseUri.port}' : '');
|
|
||||||
socketUrl =
|
|
||||||
'${baseUri.scheme == 'http' ? 'ws' : 'wss'}://${baseUri.host}$port/ws';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUris() {
|
||||||
|
if (baseUri != null && (baseUri!.scheme == 'http' || baseUri!.scheme == 'https')) {
|
||||||
|
String socketUrl;
|
||||||
|
final port = (baseUri!.hasPort ? ':${baseUri!.port}' : '');
|
||||||
|
socketUrl =
|
||||||
|
'${baseUri!.scheme == 'http' ? 'ws' : 'wss'}://${baseUri!.host}$port/ws';
|
||||||
_wsUri = Uri.parse(socketUrl);
|
_wsUri = Uri.parse(socketUrl);
|
||||||
|
} else {
|
||||||
|
baseUri = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCookie(http.Response response) {
|
||||||
|
String? rawCookie = response.headers['set-cookie'];
|
||||||
|
if (rawCookie != null) {
|
||||||
|
int index = rawCookie.indexOf(';');
|
||||||
|
headers['cookie'] =
|
||||||
|
(index == -1) ? rawCookie : rawCookie.substring(0, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> doLogin(String uri, String username, String password) async {
|
||||||
|
if(baseUri == null) {
|
||||||
|
baseUri = Uri.parse(uri);
|
||||||
|
setUris();
|
||||||
|
}
|
||||||
|
Uri loginUri = Uri.parse(baseUri!.toString() + '/login');
|
||||||
|
final form = <String, dynamic>{};
|
||||||
|
form['username'] = username;
|
||||||
|
form['password'] = password;
|
||||||
|
http.Response response = await http.post(
|
||||||
|
loginUri,
|
||||||
|
body: form,
|
||||||
|
);
|
||||||
|
if(response.statusCode == 200) {
|
||||||
|
updateCookie(response);
|
||||||
|
await storage.write(key: 'token', value: headers['cookie']);
|
||||||
|
await connect();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> connect() async {
|
Future<void> connect() async {
|
||||||
await setBearer();
|
if (connected = true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
channel = IOWebSocketChannel.connect(_wsUri, headers: headers);
|
channel = IOWebSocketChannel.connect(_wsUri, headers: headers);
|
||||||
channel.stream.listen((event) => _handleData(event), onDone: () {
|
channel.stream.listen((event) => _handleData(event), onDone: () {
|
||||||
connected = false;
|
connected = false;
|
||||||
|
|
|
@ -50,7 +50,9 @@ class CallsHomeState extends State<CallsHome> {
|
||||||
Future<void> loadData() async {
|
Future<void> loadData() async {
|
||||||
// Ensure the navigation happens in the context of this widget's subtree
|
// Ensure the navigation happens in the context of this widget's subtree
|
||||||
try {
|
try {
|
||||||
await Provider.of<Stillbox>(context, listen: false).connect();
|
final sb = Provider.of<Stillbox>(context, listen: false);
|
||||||
|
await sb.setBearer();
|
||||||
|
await sb.connect();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import 'package:calls/main.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../controller/stillbox.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class Login extends StatefulWidget {
|
class Login extends StatefulWidget {
|
||||||
const Login({super.key});
|
const Login({super.key});
|
||||||
|
@ -9,6 +12,7 @@ class Login extends StatefulWidget {
|
||||||
|
|
||||||
class _LoginState extends State<Login> {
|
class _LoginState extends State<Login> {
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
TextEditingController uriController = TextEditingController();
|
||||||
TextEditingController userController = TextEditingController();
|
TextEditingController userController = TextEditingController();
|
||||||
TextEditingController passwordController = TextEditingController();
|
TextEditingController passwordController = TextEditingController();
|
||||||
|
|
||||||
|
@ -24,6 +28,31 @@ class _LoginState extends State<Login> {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
|
Builder(builder: (context) {
|
||||||
|
if (!(Uri.base.scheme == 'http' ||
|
||||||
|
Uri.base.scheme == 'https')) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8, vertical: 10),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: uriController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: "Server URL"),
|
||||||
|
validator: (value) {
|
||||||
|
if (value != null) {
|
||||||
|
return Uri.parse(value).isAbsolute
|
||||||
|
? null
|
||||||
|
: 'Please enter a valid URL.';
|
||||||
|
} else {
|
||||||
|
return 'Please enter a valid URL.';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container();
|
||||||
|
}),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 10),
|
const EdgeInsets.symmetric(horizontal: 8, vertical: 10),
|
||||||
|
@ -60,7 +89,29 @@ class _LoginState extends State<Login> {
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
// TODO do login here
|
Provider.of<Stillbox>(context, listen: false)
|
||||||
|
.doLogin(
|
||||||
|
uriController.text,
|
||||||
|
userController.text,
|
||||||
|
passwordController.text)
|
||||||
|
.then((result) {
|
||||||
|
if (result == true && mounted) {
|
||||||
|
Navigator.pushReplacement(
|
||||||
|
context,
|
||||||
|
PageRouteBuilder(
|
||||||
|
pageBuilder: (context, animation,
|
||||||
|
secondaryAnimation) =>
|
||||||
|
const CallsHome(),
|
||||||
|
transitionsBuilder: (context, animation,
|
||||||
|
secondaryAnimation, child) {
|
||||||
|
return child;
|
||||||
|
},
|
||||||
|
transitionDuration:
|
||||||
|
const Duration(milliseconds: 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Please login.')),
|
const SnackBar(content: Text('Please login.')),
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
PODS:
|
PODS:
|
||||||
|
- audioplayers_darwin (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
|
- flutter_secure_storage_macos (6.1.1):
|
||||||
|
- FlutterMacOS
|
||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
|
- audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`)
|
||||||
|
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
audioplayers_darwin:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos
|
||||||
|
flutter_secure_storage_macos:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
|
||||||
FlutterMacOS:
|
FlutterMacOS:
|
||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c
|
||||||
|
flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9
|
||||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,6 @@
|
||||||
2C35E72338A581BA4B223314 /* Pods-RunnerTests.release.xcconfig */,
|
2C35E72338A581BA4B223314 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
308BAD42558871EC233F8F66 /* Pods-RunnerTests.profile.xcconfig */,
|
308BAD42558871EC233F8F66 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -574,6 +573,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = HPWYU9LLXA;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -706,6 +706,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = HPWYU9LLXA;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -726,6 +727,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = HPWYU9LLXA;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -8,5 +8,9 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.network.server</key>
|
<key>com.apple.security.network.server</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>keychain-access-groups</key>
|
||||||
|
<array/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -4,5 +4,9 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>keychain-access-groups</key>
|
||||||
|
<array/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -225,7 +225,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.1"
|
version: "6.2.1"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||||
|
|
|
@ -42,6 +42,7 @@ dependencies:
|
||||||
provider: ^6.1.2
|
provider: ^6.1.2
|
||||||
audioplayers: ^5.2.1
|
audioplayers: ^5.2.1
|
||||||
flutter_secure_storage: ^9.2.2
|
flutter_secure_storage: ^9.2.2
|
||||||
|
http: ^1.2.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue