aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/data/data_providers/app_launcher.dart108
-rw-r--r--lib/data/data_providers/app_launcher_info.dart21
-rw-r--r--lib/data/data_providers/app_provider.dart7
-rw-r--r--lib/export.dart1
-rw-r--r--lib/presentation/common_widget/custom_bottom_bar.dart1
-rw-r--r--lib/presentation/screens/apps/apps_content.dart58
-rw-r--r--lib/presentation/screens/home/home.dart1
7 files changed, 171 insertions, 26 deletions
diff --git a/lib/data/data_providers/app_launcher.dart b/lib/data/data_providers/app_launcher.dart
new file mode 100644
index 0000000..b0199d3
--- /dev/null
+++ b/lib/data/data_providers/app_launcher.dart
@@ -0,0 +1,108 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:protos/protos.dart';
+
+class AppLauncher {
+ final Ref ref;
+
+ late ClientChannel aglShellChannel;
+ late AglShellManagerServiceClient aglShell;
+ late ClientChannel appLauncherChannel;
+ late AppLauncherClient appLauncher;
+
+ List<String> appStack = [ 'homescreen' ];
+
+ AppLauncher({required this.ref}) {
+ aglShellChannel =
+ ClientChannel('localhost',
+ port: 14005,
+ options: ChannelOptions(credentials: ChannelCredentials.insecure()));
+
+ aglShell = AglShellManagerServiceClient(aglShellChannel);
+
+ appLauncherChannel =
+ ClientChannel('localhost',
+ port: 50052,
+ options: ChannelOptions(credentials: ChannelCredentials.insecure()));
+ appLauncher = AppLauncherClient(appLauncherChannel);
+ }
+
+ run() async {
+ getAppList();
+
+ try {
+ var response = appLauncher.getStatusEvents(StatusRequest());
+ await for (var event in response) {
+ if (event.hasApp()) {
+ AppStatus app_status = event.app;
+ debugPrint("Got app status:");
+ debugPrint("$app_status");
+ if (app_status.hasId() && app_status.hasStatus()) {
+ if (app_status.status == "started") {
+ activateApp(app_status.id);
+ } else if (app_status.status == "terminated") {
+ deactivateApp(app_status.id);
+ }
+ }
+ }
+ }
+ } catch (e) {
+ print(e);
+ }
+ }
+
+ getAppList() async {
+ try {
+ var response = await appLauncher.listApplications(ListRequest());
+ List<AppLauncherInfo> apps = [];
+ for (AppInfo info in response.apps) {
+ debugPrint("Got app:");
+ debugPrint("$info");
+ // Existing icons are currently not usable, so leave blank for now
+ apps.add(AppLauncherInfo(id: info.id, name: info.name, icon: "", internal: false));
+ }
+ apps.sort((a, b) => a.name.compareTo(b.name));
+
+ // Add built-in app widgets
+ apps.insert(0, AppLauncherInfo(id: "clock", name: "Clock", icon: "clock.svg", internal: true));
+ apps.insert(0, AppLauncherInfo(id: "weather", name: "Weather", icon: "weather.svg", internal: true));
+
+ ref.read(appLauncherListProvider.notifier).update(apps);
+ } catch (e) {
+ print(e);
+ }
+ }
+
+ void startApp(String id) async {
+ await appLauncher.startApplication(StartRequest(id: id));
+ }
+
+ addAppToStack(String id) {
+ if (!appStack.contains(id)) {
+ appStack.add(id);
+ } else {
+ int current = appStack.indexOf(id);
+ if (current != (appStack.length - 1)) {
+ appStack.removeAt(current);
+ appStack.add(id);
+ }
+ }
+ }
+
+ activateApp(String id) async {
+ if (appStack.last != id) {
+ var req = ActivateRequest(appId: id);
+ var response = aglShell.activateApp(req);
+ addAppToStack(id);
+ }
+ }
+
+ deactivateApp(String id) async {
+ if (appStack.contains(id)) {
+ appStack.remove(id);
+ if (appStack.isNotEmpty) {
+ activateApp(appStack.last);
+ }
+ }
+ }
+
+}
diff --git a/lib/data/data_providers/app_launcher_info.dart b/lib/data/data_providers/app_launcher_info.dart
new file mode 100644
index 0000000..4d79cfe
--- /dev/null
+++ b/lib/data/data_providers/app_launcher_info.dart
@@ -0,0 +1,21 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class AppLauncherInfo {
+ final String id;
+ final String name;
+ final String icon;
+ final bool internal;
+
+ AppLauncherInfo({required this.id, required this.name, required this.icon, required this.internal});
+}
+
+class AppLauncherList extends Notifier<List<AppLauncherInfo>> {
+ @override
+ List<AppLauncherInfo> build() {
+ return [];
+ }
+
+ void update(List<AppLauncherInfo> newAppList) {
+ state = newAppList;
+ }
+}
diff --git a/lib/data/data_providers/app_provider.dart b/lib/data/data_providers/app_provider.dart
index cfda370..1670eba 100644
--- a/lib/data/data_providers/app_provider.dart
+++ b/lib/data/data_providers/app_provider.dart
@@ -5,6 +5,7 @@ import 'package:flutter_ics_homescreen/data/data_providers/units_notifier.dart';
import 'package:flutter_ics_homescreen/data/data_providers/audio_notifier.dart';
import 'package:flutter_ics_homescreen/data/data_providers/users_notifier.dart';
import 'package:flutter_ics_homescreen/data/data_providers/val_client.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/app_launcher.dart';
import 'package:flutter_ics_homescreen/export.dart';
import '../models/users.dart';
@@ -43,6 +44,12 @@ final valClientProvider = Provider((ref) {
return ValClient(config: config, ref: ref);
});
+final appLauncherProvider = Provider((ref) {
+ return AppLauncher(ref: ref);
+});
+
+final appLauncherListProvider = NotifierProvider<AppLauncherList, List<AppLauncherInfo>>(AppLauncherList.new);
+
final vehicleProvider =
NotifierProvider<VehicleNotifier, Vehicle>(VehicleNotifier.new);
diff --git a/lib/export.dart b/lib/export.dart
index 17cab07..1e07f3f 100644
--- a/lib/export.dart
+++ b/lib/export.dart
@@ -1,6 +1,7 @@
export 'data/data_providers/app.dart';
export 'data/data_providers/app_config_provider.dart';
export 'data/data_providers/app_provider.dart';
+export 'data/data_providers/app_launcher_info.dart';
export 'presentation/router/routes/routes.dart';
export 'data/theme/theme.dart';
diff --git a/lib/presentation/common_widget/custom_bottom_bar.dart b/lib/presentation/common_widget/custom_bottom_bar.dart
index 64684e9..61a7e20 100644
--- a/lib/presentation/common_widget/custom_bottom_bar.dart
+++ b/lib/presentation/common_widget/custom_bottom_bar.dart
@@ -44,6 +44,7 @@ class CustomBottomBarState extends ConsumerState<CustomBottomBar> {
setState(() {
selectedNav = title;
});
+ ref.read(appLauncherProvider).activateApp("homescreen");
ref.read(currentTimeProvider.notifier).isYearChanged = false;
ref.read(appProvider.notifier).update((state) => state = status);
}
diff --git a/lib/presentation/screens/apps/apps_content.dart b/lib/presentation/screens/apps/apps_content.dart
index fe6e3b0..b0afda1 100644
--- a/lib/presentation/screens/apps/apps_content.dart
+++ b/lib/presentation/screens/apps/apps_content.dart
@@ -1,48 +1,54 @@
import 'package:flutter_ics_homescreen/export.dart';
import 'package:flutter_ics_homescreen/presentation/screens/apps/widgets/app_button.dart';
-class Apps extends StatefulWidget {
+class Apps extends ConsumerStatefulWidget {
const Apps({super.key});
@override
- State<Apps> createState() => _AppsState();
+ ConsumerState<Apps> createState() => _AppsState();
}
-class _AppsState extends State<Apps> {
- onPressed({required String type}) {
- if (type == "weather") {
- context.flow<AppState>().update((next) => AppState.weather);
- } else if (type == "clock") {
- context.flow<AppState>().update((next) => AppState.clock);
+class _AppsState extends ConsumerState<Apps> {
+ onPressed({required bool internal, required String id}) {
+ if (internal) {
+ if (id == "weather") {
+ context.flow<AppState>().update((next) => AppState.weather);
+ } else if (id == "clock") {
+ context.flow<AppState>().update((next) => AppState.clock);
+ }
+ } else {
+ ref.read(appLauncherProvider).startApp(id);
}
}
@override
Widget build(BuildContext context) {
+ var apps = ref.watch(appLauncherListProvider);
+
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const CommonTitle(title: "Applications"),
Padding(
padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 148),
- child: Wrap(
- children: [
- AppButton(
- image: "weather.svg",
- title: "Weather",
- onPressed: () {
- onPressed(type: "weather");
- },
- ),
- AppButton(
- image: "clock.svg",
- title: "Clock",
- onPressed: () {
- onPressed(type: "clock");
- },
- )
- ],
- ),
+ child: GridView.builder(
+ scrollDirection: Axis.vertical,
+ shrinkWrap: true,
+ itemCount: apps.length,
+ gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+ crossAxisCount: 3),
+ itemBuilder: (context, index) {
+ return GridTile(
+ child: Container(
+ alignment: Alignment.center,
+ child: AppButton(
+ title: apps[index].name,
+ image: apps[index].icon.isNotEmpty ? apps[index].icon : "app-generic.svg",
+ onPressed: () {
+ onPressed(internal: apps[index].internal, id: apps[index].id);
+ },
+ )));
+ })
),
// Center(
// child: SizedBox(
diff --git a/lib/presentation/screens/home/home.dart b/lib/presentation/screens/home/home.dart
index 86da46f..3d80f92 100644
--- a/lib/presentation/screens/home/home.dart
+++ b/lib/presentation/screens/home/home.dart
@@ -13,6 +13,7 @@ class HomeScreen extends ConsumerStatefulWidget {
class HomeScreenState extends ConsumerState<HomeScreen> {
@override
void initState() {
+ ref.read(appLauncherProvider).run();
super.initState();
}