Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux support #174

Merged
merged 6 commits into from
May 28, 2024
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
3 changes: 3 additions & 0 deletions .metadata
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ migration:
- platform: root
create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
- platform: linux
create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
- platform: windows
create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ multiple versions on your local machine, or simply use this submodule to build i
2. open an android or ios emulator
3. run `flutter run --debug`

Building for Linux requires installing the following packages for the [SQFlite database](https://pub.dev/packages/sqflite_common_ffi#linux):

```sudo apt-get -y install libsqlite3-0 libsqlite3-dev```

## Contributing

I am an independent developer and do not have professional expertise in writing
Expand Down
2 changes: 1 addition & 1 deletion lib/provider/app_reminder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class AppReminderViewModel extends ChangeNotifier
Future<bool> processAppReminder(L10n? l10n) async {
final reminder = this.reminder;
if (reminder.enabled && l10n != null) {
if (await NotificationService().requestPermissions() != true) {
if (await NotificationService().requestPermissions() == false) {
return false;
}
switch (reminder.type) {
Expand Down
48 changes: 46 additions & 2 deletions lib/reminders/notification_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,40 +172,84 @@ class NotificationIosChannelData
interruptionLevel: InterruptionLevel.passive);
}

class NotificationLinuxChannelData
implements NotificationChannelDataABC<LinuxNotificationDetails> {
final LinuxNotificationDetails? _debug;
final LinuxNotificationDetails? _habitReminder;
final LinuxNotificationDetails? _appReminder;
final LinuxNotificationDetails? _appDebugger;

const NotificationLinuxChannelData({
LinuxNotificationDetails? debug,
LinuxNotificationDetails? habitReminder,
LinuxNotificationDetails? appReminder,
LinuxNotificationDetails? appDebugger,
}) : _debug = debug,
_habitReminder = habitReminder,
_appReminder = appReminder,
_appDebugger = appDebugger;

@override
LinuxNotificationDetails get debug =>
_debug ?? const LinuxNotificationDetails();

@override
LinuxNotificationDetails get habitReminder =>
_habitReminder ?? const LinuxNotificationDetails();

@override
LinuxNotificationDetails get appReminder =>
_appReminder ?? const LinuxNotificationDetails();

@override
LinuxNotificationDetails get appDebugger =>
_appDebugger ?? const LinuxNotificationDetails();
}

class NotificationChannelData extends ChangeNotifier
implements NotificationChannelDataABC<NotificationDetails> {
final NotificationAndroidChannelData _androidChannel;
final NotificationIosChannelData _iosChannel;
final NotificationLinuxChannelData _linuxChannel;

NotificationChannelData({
NotificationAndroidChannelData? androidChannel,
NotificationIosChannelData? iosChannel,
NotificationLinuxChannelData? linuxChannel,
}) : _androidChannel =
androidChannel ?? const NotificationAndroidChannelData(),
_iosChannel = iosChannel ?? const NotificationIosChannelData();
_iosChannel = iosChannel ?? const NotificationIosChannelData(),
_linuxChannel = linuxChannel ?? const NotificationLinuxChannelData();

@override
NotificationDetails get debug => NotificationDetails(
android: _androidChannel.debug,
iOS: _iosChannel.debug,
linux: _linuxChannel.debug,
macOS: _iosChannel.debug,
);

@override
NotificationDetails get habitReminder => NotificationDetails(
android: _androidChannel.habitReminder, iOS: _iosChannel.habitReminder);
android: _androidChannel.habitReminder,
iOS: _iosChannel.habitReminder,
linux: _linuxChannel.habitReminder,
macOS: _iosChannel.debug,
);

@override
NotificationDetails get appReminder => NotificationDetails(
android: _androidChannel.appReminder,
iOS: _iosChannel.appReminder,
linux: _linuxChannel.appReminder,
macOS: _iosChannel.appReminder,
);

@override
NotificationDetails get appDebugger => NotificationDetails(
android: _androidChannel.appDebugger,
iOS: _iosChannel.appDebugger,
linux: _linuxChannel.appReminder,
macOS: _iosChannel.appDebugger,
);
}
36 changes: 36 additions & 0 deletions lib/reminders/notification_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ abstract interface class NotificationService implements AsyncInitialization {
factory NotificationService() {
if (_instance != null) return _instance!;
if (Platform.isWindows) return _instance = const FakeNotificationService();
if (Platform.isLinux) return _instance = const LinuxNotificationService();
return _instance = const NotificationServiceImpl();
}
}
Expand Down Expand Up @@ -131,11 +132,16 @@ final class NotificationServiceImpl implements NotificationService {
],
);

// linux setting
const linuxSettings =
LinuxInitializationSettings(defaultActionName: "Open notification");

// combine settings
final initializationSettings = InitializationSettings(
android: androidSettings,
iOS: darwinSettings,
macOS: darwinSettings,
linux: linuxSettings,
);

await plugin.initialize(
Expand Down Expand Up @@ -355,6 +361,36 @@ final class NotificationServiceImpl implements NotificationService {
}
}

final class LinuxNotificationService extends NotificationServiceImpl {
const LinuxNotificationService();

//TODO: Lame implementation; plugin doesn't support scheduling on Linux,
// need to find some solutions.
@override
Future<bool> regrAppReminderInDaily(
{required String title,
required String subtitle,
required TimeOfDay timeOfDay,
required NotificationDetails details,
Duration? timeout = NotificationServiceImpl.defaultTimeout}) =>
Future.value(false);

//TODO: Lame implementation; plugin doesn't support scheduling on Linux,
// need to find some solutions.
@override
Future<bool> regrHabitReminder<T>(
{required DBID id,
required HabitUUID uuid,
required String name,
String? quest,
required HabitReminder reminder,
required HabitDate? lastUntrackDate,
required NotificationDetails details,
DateTime? crtDate,
Duration? timeout = NotificationServiceImpl.defaultTimeout}) =>
Future.value(false);
}

final class FakeNotificationService implements NotificationService {
const FakeNotificationService();

Expand Down
1 change: 1 addition & 0 deletions linux/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flutter/ephemeral
139 changes: 139 additions & 0 deletions linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)

# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "mhabit")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "io.github.friesi23.mhabit")

# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)

# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")

# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()

# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()

# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()

# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})

# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)

add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")

# Define the application target. To change its name, change BINARY_NAME above,
# not the value here, or `flutter run` will no longer work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)

# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})

# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)

# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)

# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)


# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)


# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()

# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)

set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")

install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)

install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)

install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)

foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endforeach(bundled_library)

# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)

# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
Loading
Loading