Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<application
android:label="front"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
Expand Down Expand Up @@ -41,5 +42,7 @@
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
<!-- Required to check if Even G1 app is installed -->
<package android:name="com.even.g1" />
</queries>
</manifest>
6 changes: 6 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>com.even.g1</string>
<string>eveng1</string>
<string>even-g1</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
Expand Down
150 changes: 131 additions & 19 deletions lib/screens/landing_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import 'dart:async';
import 'package:even_realities_g1/even_realities_g1.dart';
import 'package:flutter/material.dart';
import 'package:front/services/audio_pipeline.dart';
import 'package:android_intent_plus/android_intent.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:io';
import '../widgets/g1_connection.dart';
import '../services/websocket_service.dart';
import 'package:front/services/lc3_decoder.dart';

import '../models/api_models.dart';
import '../services/calendar_service.dart';
import '../services/phone_audio_service.dart';
import '../services/rest_api_service.dart';
import '../services/websocket_service.dart';
import '../widgets/g1_connection.dart';
import '../widgets/side_panel.dart';
import 'login_screen.dart';
import 'register_screen.dart';
Expand Down Expand Up @@ -60,6 +63,94 @@ class _LandingScreenState extends State<LandingScreen> {
final List<String> _displayedSentences = [];
static const int _maxDisplayedSentences = 4;

// Show confirmation dialog before switching to Even app
Future<void> _switchToEvenApp() async {
if (_isRecording.value) {
return;
}
final confirmed = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("Switch app"),
content: const Text(
"Glasses will disconnect and the Even app will open. Continue?",
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text("Cancel"),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text("Open Even"),
),
],
);
},
);
if (confirmed != true) return;
if (_manager.isConnected) {
await _manager.disconnect();
}
await _openEvenApp();
}

// Open the Even app
// Android: check if app is installed via intent URI before launching,
// show error dialog if not found (no Play Store fallback)
// iOS: attempt possible deep link schemes, fallback to App Store
Future<void> _openEvenApp() async {
if (Platform.isAndroid) {
try {
const intent = AndroidIntent(
action: 'android.intent.action.MAIN',
package: 'com.even.g1',
componentName: 'com.even.g1.MainActivity',
flags: <int>[0x10000000],
);
await intent.launch();
} catch (_) {
if (mounted) {
showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Even app not found'),
content: const Text(
'The Even G1 app is not installed on this device.',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
}
}
} else if (Platform.isIOS) {
const schemes = [
'com.even.g1://',
'eveng1://',
'even-g1://',
];

for (final scheme in schemes) {
final uri = Uri.parse(scheme);

if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
return;
}
}

// jos appia ei voitu avata mennään App Storeen
final store = Uri.parse('https://apps.apple.com/app/id6499140518');
await launchUrl(store, mode: LaunchMode.externalApplication);
}
}

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -651,23 +742,44 @@ class _LandingScreenState extends State<LandingScreen> {
),
const SizedBox(height: 8),
Center(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 5,
),
decoration: BoxDecoration(
border: Border.all(color: Colors.black12),
borderRadius: BorderRadius.circular(8),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.battery_full, size: 18),
SizedBox(width: 8),
Text('G1 smart glasses'),
],
),
child: ValueListenableBuilder<bool>(
valueListenable: _isRecording,
builder: (context, isRecording, _) {
return GestureDetector(
onTap:
isRecording ? null : _switchToEvenApp,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 5,
),
decoration: BoxDecoration(
border: Border.all(
color: isRecording
? Colors.grey
: Colors.black12,
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.battery_full,
size: 18),
const SizedBox(width: 8),
Text(
'G1 smart glasses',
style: TextStyle(
color: isRecording
? Colors.grey
: Colors.black,
),
),
],
),
),
);
},
),
),
],
Expand Down
4 changes: 4 additions & 0 deletions linux/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
#include "generated_plugin_registrant.h"

#include <flutter_sound/flutter_sound_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>

void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_sound_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSoundPlugin");
flutter_sound_plugin_register_with_registrar(flutter_sound_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
}
1 change: 1 addition & 0 deletions linux/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

list(APPEND FLUTTER_PLUGIN_LIST
flutter_sound
url_launcher_linux
)

list(APPEND FLUTTER_FFI_PLUGIN_LIST
Expand Down
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import Foundation

import flutter_blue_plus_darwin
import flutter_sound
import url_launcher_macos

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
FlutterSoundPlugin.register(with: registry.registrar(forPlugin: "FlutterSoundPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}
80 changes: 76 additions & 4 deletions pubspec.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
android_intent_plus:
dependency: "direct main"
description:
name: android_intent_plus
sha256: e1c62bb41c90e15083b7fb84dc327fe90396cc9c1445b55ff1082144fabfb4d9
url: "https://pub.dev"
source: hosted
version: "4.0.3"
args:
dependency: transitive
description:
Expand Down Expand Up @@ -315,10 +323,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
Expand Down Expand Up @@ -560,10 +568,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.9"
timezone:
dependency: transitive
description:
Expand All @@ -580,6 +588,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8
url: "https://pub.dev"
source: hosted
version: "6.3.2"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611"
url: "https://pub.dev"
source: hosted
version: "6.3.28"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0"
url: "https://pub.dev"
source: hosted
version: "6.4.1"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a
url: "https://pub.dev"
source: hosted
version: "3.2.2"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18"
url: "https://pub.dev"
source: hosted
version: "3.2.5"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f
url: "https://pub.dev"
source: hosted
version: "2.4.2"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
vector_math:
dependency: transitive
description:
Expand Down
3 changes: 3 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8

url_launcher: ^6.3.1
android_intent_plus: ^4.0.0

# Local path dependency
device_calendar: ^4.3.3
even_realities_g1:
Expand Down
3 changes: 3 additions & 0 deletions windows/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

#include <flutter_sound/flutter_sound_plugin_c_api.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>

void RegisterPlugins(flutter::PluginRegistry* registry) {
FlutterSoundPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSoundPluginCApi"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}
1 change: 1 addition & 0 deletions windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
flutter_sound
permission_handler_windows
url_launcher_windows
)

list(APPEND FLUTTER_FFI_PLUGIN_LIST
Expand Down