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
16 changes: 12 additions & 4 deletions app/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ android {
ndkVersion "28.2.13676358"

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true

sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = '1.8'
jvmTarget = JavaVersion.VERSION_17.toString()
}

sourceSets {
Expand All @@ -54,6 +56,8 @@ android {
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

multiDexEnabled true
}

buildTypes {
Expand All @@ -69,7 +73,11 @@ flutter {
source '../..'
}

dependencies {}
dependencies {
implementation 'androidx.window:window:1.0.0'
implementation 'androidx.window:window-java:1.0.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
}

// See: https://developer.android.com/build/configure-apk-splits
import com.android.build.OutputFile
Expand Down
21 changes: 21 additions & 0 deletions app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- notification permissions -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<!-- Internet access and state -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Expand Down Expand Up @@ -37,6 +46,18 @@
android:authorities="${applicationId}.workmanager-init"
android:enabled="false"
android:exported="false"/>

<!-- Flutter Local Notifications plugin receivers -->
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility?hl=en and
Expand Down
11 changes: 11 additions & 0 deletions app/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,14 @@ subprojects {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

buildscript {
repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:8.12.0'
}
}
49 changes: 49 additions & 0 deletions app/lib/context.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'dart:convert';

import 'package:stride/bridge/api/context.dart' as context;
import 'package:stride/notifications.dart';

class RustContext {
static late Stream<String> _stream;
Expand All @@ -7,6 +10,52 @@ class RustContext {

static Future<void> init() async {
_stream = context.createContext().asBroadcastStream();

_stream.listen((event) async {
final json = jsonDecode(event) as Map<String, dynamic>;
if (json['method'] == 'stride.notification.repository.changed') {
final params = json['params'] as Map<String, dynamic>;
final changes = params['changes'] as List<dynamic>;
for (final change in changes) {
final taskId = change['task-id'] as String;
var title = change['title'] as String?;

String? body;

var isNewTask = false;

final fields = change['fields'] as List<dynamic>;
for (final field in fields) {
final type = field['type'] as String;
final current = field['current'] as String?;
final previous = field['previous'] as String?;

if (type == 'status' && previous == null && current == 'pending') {
isNewTask = true;
continue;
}

if (type == 'title') {
title ??= current;

if (previous == null) {
continue;
}
}

body ??= '';

// ignore: use_string_buffers
body += '$type: ${previous ?? 'none'} -> ${current ?? 'none'}\n';
}

await NotificationService.show(
'${isNewTask ? "New task" : "Task change"}: ${title ?? "Task($taskId)"}',
body,
);
}
}
});
}

static Future<void> execute(String method, String args) async {
Expand Down
2 changes: 2 additions & 0 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:stride/bridge/api/plugin_manager.dart' as pm;
import 'package:stride/bridge/api/settings.dart';
import 'package:stride/bridge/frb_generated.dart';
import 'package:stride/context.dart';
import 'package:stride/notifications.dart';
import 'package:stride/routes/initial_route.dart';
import 'package:stride/routes/logging_routes.dart';
import 'package:stride/routes/tasks_route.dart';
Expand Down Expand Up @@ -52,6 +53,7 @@ Future<void> main() async {
await RustContext.init();

await Background.init();
await NotificationService.init();

final pluginPath = path.join(supportPath, 'plugins');
await pm.load(pluginPath: pluginPath);
Expand Down
75 changes: 75 additions & 0 deletions app/lib/notifications.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'dart:io';
import 'dart:math';

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationService {
static final FlutterLocalNotificationsPlugin _plugin =
FlutterLocalNotificationsPlugin();

static Future<void> init() async {
const androidSettings = AndroidInitializationSettings(
'@mipmap/ic_launcher',
);
const iosSettings = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const macosSettings = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);

const linuxSettings = LinuxInitializationSettings(
defaultActionName: 'Stride',
);

const settings = InitializationSettings(
android: androidSettings,
iOS: iosSettings,
macOS: macosSettings,
linux: linuxSettings,
);

await _plugin.initialize(settings: settings);
}

static Future<void> show(String title, String? body) async {
if (Platform.isAndroid) {
await _plugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()!
.requestNotificationsPermission();
}

final androidDetails = AndroidNotificationDetails(
'stride_background',
'Background notifications',
channelDescription: 'Notifications about background activities.',
importance: Importance.max,
priority: Priority.high,
ticker: 'Stride background notification',
);

final details = NotificationDetails(
android: androidDetails,
iOS: const DarwinNotificationDetails(),
macOS: const DarwinNotificationDetails(),
linux: const LinuxNotificationDetails(),
);

final uniqueId =
DateTime.now().millisecondsSinceEpoch.remainder(100000) * 100 +
Random().nextInt(100);

await _plugin.show(
id: uniqueId,
title: title,
body: body,
notificationDetails: details,
);
}
}
1 change: 1 addition & 0 deletions app/lib/widgets/custom_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
} else if (output.error != null) {
return Icon(Icons.sync_problem);
} else if (output.done) {
context.read<TaskBloc>().add(TaskFetchEvent());
return Icon(Icons.sync);
} else {
return const InfiniteRotationAnimation(
Expand Down
2 changes: 2 additions & 0 deletions app/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import FlutterMacOS
import Foundation

import file_picker
import flutter_local_notifications
import url_launcher_macos
import workmanager_apple

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WorkmanagerPlugin.register(with: registry.registrar(forPlugin: "WorkmanagerPlugin"))
}
60 changes: 54 additions & 6 deletions app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,10 @@ packages:
dependency: transitive
description:
name: dbus
sha256: "792974a4007974fbc5c1b5433eb2330a9db3e368c3f906253af4c007d0f49a91"
sha256: "0ce9b0a839e6dee59a37a623d2fc26a35bbbe6404213e419b0d6411023d62645"
url: "https://pub.dev"
source: hosted
version: "0.7.13"
version: "0.7.14"
fake_async:
dependency: transitive
description:
Expand Down Expand Up @@ -294,6 +294,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: "1447ba911c60f2ba3f25dae1af151ec187162566b0f57e37771bf0b400f013ad"
url: "https://pub.dev"
source: hosted
version: "22.3.0"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: "9ca97e63776f29ab1b955725c09999fc2c150523269db150c39274f2a43c5a8b"
url: "https://pub.dev"
source: hosted
version: "8.0.1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "43c3761d916c9bd3d5c7ebbc44d82f4990329840c0c5d62ad5260cc1b5d399bd"
url: "https://pub.dev"
source: hosted
version: "12.2.0"
flutter_local_notifications_web:
dependency: transitive
description:
name: flutter_local_notifications_web
sha256: "516afaf97a2d1e67a036c6617321b00d205d72f7a67b6eccf936cd565f985878"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_local_notifications_windows:
dependency: transitive
description:
name: flutter_local_notifications_windows
sha256: "6f43bdd03b171b7a90f22647506fea33e2bb12294b7c7c7a3d690e960a382945"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
flutter_native_splash:
dependency: "direct main"
description:
Expand Down Expand Up @@ -412,10 +452,10 @@ packages:
dependency: transitive
description:
name: image
sha256: "6300175e00616bbc832e2fc91bfa4d776af5402c81c7151bee6905bb08473c52"
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
url: "https://pub.dev"
source: hosted
version: "4.9.1"
version: "4.8.0"
intersperse:
dependency: "direct main"
description:
Expand Down Expand Up @@ -804,6 +844,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.12"
timezone:
dependency: transitive
description:
name: timezone
sha256: "981d1020d6ef8fe1e7b3de5054e5b25579ae7c403d7734adc508ffc47668e9cb"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
typed_data:
dependency: transitive
description:
Expand Down Expand Up @@ -1008,10 +1056,10 @@ packages:
dependency: transitive
description:
name: xml
sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4"
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
version: "6.6.1"
yaml:
dependency: transitive
description:
Expand Down
3 changes: 2 additions & 1 deletion app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ publish_to: "none"
homepage: https://github.com/stride-tasks/stride
repository: https://github.com/stride-tasks/stride

version: 0.0.1+1
version: 0.0.1+2

environment:
sdk: ">=3.10.0 <4.0.0"
Expand Down Expand Up @@ -33,6 +33,7 @@ dependencies:
flutter_native_splash: ^2.4.8
workmanager: ^0.10.7
async: ^2.13.0
flutter_local_notifications: ^22.3.0

dev_dependencies:
flutter_test:
Expand Down
1 change: 1 addition & 0 deletions app/windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
)

list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_local_notifications_windows
jni
stride_flutter_bridge
)
Expand Down
Loading