├── src
├── lib
│ ├── utils
│ │ ├── app_flavour
│ │ │ └── app_flavour.dart
│ │ ├── enum
│ │ │ ├── app_launch_transition.dart
│ │ │ ├── corner_button_type.dart
│ │ │ └── leafy_theme_style.dart
│ │ ├── log
│ │ │ ├── logable_mixin.dart
│ │ │ ├── pretty_console_output.dart
│ │ │ ├── get_logger.dart
│ │ │ ├── file_output.dart
│ │ │ └── simple_log_printer.dart
│ │ ├── extensions
│ │ │ └── iterable_extensions.dart
│ │ ├── app_goes_to_background_aware
│ │ │ └── app_goes_to_background_aware.dart
│ │ ├── preferences
│ │ │ └── shared_preferences.dart
│ │ └── dialogs
│ │ │ └── confirm
│ │ │ └── actions_dialog.dart
│ ├── database
│ │ └── leafy_notes_db
│ │ │ ├── src
│ │ │ ├── one_to_manys.dart
│ │ │ ├── daos.dart
│ │ │ ├── models.dart
│ │ │ ├── tables.dart
│ │ │ ├── repositories
│ │ │ │ └── repositories.dart
│ │ │ ├── one_to_many
│ │ │ │ └── folder_with_notes.dart
│ │ │ ├── models
│ │ │ │ ├── note
│ │ │ │ │ ├── table
│ │ │ │ │ │ ├── sorts.dart
│ │ │ │ │ │ └── note_table.dart
│ │ │ │ │ ├── repository
│ │ │ │ │ │ ├── note_repository.dart
│ │ │ │ │ │ └── note_repository_impl.dart
│ │ │ │ │ ├── dao
│ │ │ │ │ │ └── note_dao.g.dart
│ │ │ │ │ └── model
│ │ │ │ │ │ ├── note_converter.dart
│ │ │ │ │ │ └── note_model.dart
│ │ │ │ └── folder
│ │ │ │ │ ├── dao
│ │ │ │ │ └── folder_dao.g.dart
│ │ │ │ │ ├── table
│ │ │ │ │ ├── sorts.dart
│ │ │ │ │ └── folder_table.dart
│ │ │ │ │ ├── repository
│ │ │ │ │ └── folder_repository.dart
│ │ │ │ │ └── model
│ │ │ │ │ ├── folder_converter.dart
│ │ │ │ │ └── folder_model.dart
│ │ │ └── leafy_notes_db.dart
│ │ │ ├── extensions
│ │ │ ├── iterable_extensions.dart
│ │ │ └── map_extensions.dart
│ │ │ └── leafy_notes_database.dart
│ ├── main_dev.dart
│ ├── main_prod.dart
│ ├── module
│ │ ├── intro
│ │ │ ├── tutorial
│ │ │ │ ├── domain
│ │ │ │ │ ├── slide_type.dart
│ │ │ │ │ └── slide_controller.dart
│ │ │ │ ├── tutorial_binding.dart
│ │ │ │ └── tutorial_page.dart
│ │ │ ├── intro_binding.dart
│ │ │ └── intro_page.dart
│ │ ├── home
│ │ │ ├── home_binding.dart
│ │ │ ├── widget
│ │ │ │ ├── corner_button
│ │ │ │ │ ├── _full_screen_box.dart
│ │ │ │ │ ├── _other_apps_list.dart
│ │ │ │ │ └── _configured_icon_button.dart
│ │ │ │ ├── home_widgets
│ │ │ │ │ ├── home_top_widget.dart
│ │ │ │ │ ├── time_progress
│ │ │ │ │ │ └── time_progress_type.dart
│ │ │ │ │ └── home_date.dart
│ │ │ │ ├── google_search
│ │ │ │ │ ├── google_search_input.dart
│ │ │ │ │ └── google_search_results.dart
│ │ │ │ ├── horizontal_swipe_app_icon.dart
│ │ │ │ ├── user_app_button.dart
│ │ │ │ └── curved_background.dart
│ │ │ └── utils
│ │ │ │ └── gesture_processer.dart
│ │ ├── startup
│ │ │ ├── startup_binding.dart
│ │ │ ├── startup_page.dart
│ │ │ └── startup_controller.dart
│ │ ├── home_notes
│ │ │ └── notes
│ │ │ │ ├── folders
│ │ │ │ ├── home_note_folders_binding.dart
│ │ │ │ ├── widget
│ │ │ │ │ ├── title
│ │ │ │ │ │ └── home_note_folders_title.dart
│ │ │ │ │ └── list
│ │ │ │ │ │ └── home_note_folder_container.dart
│ │ │ │ └── home_note_folders_page.dart
│ │ │ │ ├── notes
│ │ │ │ ├── home_notes_binding.dart
│ │ │ │ ├── widget
│ │ │ │ │ ├── list
│ │ │ │ │ │ ├── home_notes_empty_widget.dart
│ │ │ │ │ │ └── home_note_container.dart
│ │ │ │ │ └── title
│ │ │ │ │ │ └── home_notes_title.dart
│ │ │ │ └── home_notes_page.dart
│ │ │ │ └── note
│ │ │ │ ├── home_note_binding.dart
│ │ │ │ ├── home_note_page.dart
│ │ │ │ └── widget
│ │ │ │ └── body
│ │ │ │ └── home_note_body.dart
│ │ ├── home_settings
│ │ │ ├── home_settings_binding.dart
│ │ │ ├── oss
│ │ │ │ ├── home_settings_oss_binding.dart
│ │ │ │ ├── home_settings_oss_page.dart
│ │ │ │ ├── title
│ │ │ │ │ └── home_settings_oss_title.dart
│ │ │ │ ├── home_settings_oss_controller.dart
│ │ │ │ └── body
│ │ │ │ │ └── settings_oss_body.dart
│ │ │ ├── about
│ │ │ │ ├── home_settings_about_binding.dart
│ │ │ │ ├── body
│ │ │ │ │ ├── oss
│ │ │ │ │ │ └── oss.dart
│ │ │ │ │ ├── info
│ │ │ │ │ │ ├── gmail.dart
│ │ │ │ │ │ ├── github.dart
│ │ │ │ │ │ └── telegram.dart
│ │ │ │ │ └── settings_about_body.dart
│ │ │ │ ├── home_settings_about_page.dart
│ │ │ │ ├── title
│ │ │ │ │ └── home_settings_about_title.dart
│ │ │ │ └── home_settings_about_controller.dart
│ │ │ ├── widgets
│ │ │ │ ├── home_settings_widgets_binding.dart
│ │ │ │ ├── home_settings_widgets_page.dart
│ │ │ │ ├── title
│ │ │ │ │ └── home_settings_widgets_title.dart
│ │ │ │ ├── widget
│ │ │ │ │ └── leafy_section_enabled_state_item.dart
│ │ │ │ ├── body
│ │ │ │ │ ├── time_progress
│ │ │ │ │ │ ├── time_progress_type_state.dart
│ │ │ │ │ │ └── time_progress_enabled_state.dart
│ │ │ │ │ ├── clock
│ │ │ │ │ │ └── clock_enabled_state.dart
│ │ │ │ │ ├── calendar
│ │ │ │ │ │ └── calendar_enabled_state.dart
│ │ │ │ │ └── corner_apps
│ │ │ │ │ │ ├── left_corner_app_enabled_state.dart
│ │ │ │ │ │ └── right_corner_app_enabled_state.dart
│ │ │ │ └── home_settings_widgets_controller.dart
│ │ │ ├── widget
│ │ │ │ ├── settings_body
│ │ │ │ │ ├── about
│ │ │ │ │ │ └── about.dart
│ │ │ │ │ ├── common
│ │ │ │ │ │ ├── theme.dart
│ │ │ │ │ │ ├── language.dart
│ │ │ │ │ │ └── vibration.dart
│ │ │ │ │ ├── widget
│ │ │ │ │ │ └── theme.dart
│ │ │ │ │ ├── take_tutorial
│ │ │ │ │ │ └── take_tutorial.dart
│ │ │ │ │ ├── home_widgets
│ │ │ │ │ │ └── home_widgets.dart
│ │ │ │ │ ├── select_default_launcher
│ │ │ │ │ │ └── select_default_launcher.dart
│ │ │ │ │ └── swipe_apps
│ │ │ │ │ │ ├── swipe_to_left_app.dart
│ │ │ │ │ │ └── swipe_to_right_app.dart
│ │ │ │ └── settings_title
│ │ │ │ │ └── settings_title.dart
│ │ │ ├── oss_license
│ │ │ │ ├── home_settings_oss_license_binding.dart
│ │ │ │ ├── title
│ │ │ │ │ └── home_settings_oss_license_title.dart
│ │ │ │ ├── home_settings_oss_license_page.dart
│ │ │ │ ├── home_settings_oss_license_controller.dart
│ │ │ │ └── body
│ │ │ │ │ └── settings_oss_license_body.dart
│ │ │ ├── home_settings_page.dart
│ │ │ └── home_settings_controller.dart
│ │ └── app_picker
│ │ │ ├── app_picker_controller.dart
│ │ │ ├── app_picker_binding.dart
│ │ │ └── widget
│ │ │ ├── app_picker_button.dart
│ │ │ └── app_picker_fade.dart
│ ├── services
│ │ ├── applications
│ │ │ ├── application.dart
│ │ │ ├── leafy_application.dart
│ │ │ ├── exceptions
│ │ │ │ ├── app_is_not_in_the_list_exception.dart
│ │ │ │ └── unable_to_uninstall_a_system_app_exception.dart
│ │ │ └── installed_application.dart
│ │ ├── device_vibration
│ │ │ └── device_vibration.dart
│ │ ├── oss_licenses
│ │ │ ├── oss_license.dart
│ │ │ └── oss_licenses_service.dart
│ │ ├── share
│ │ │ └── share_service.dart
│ │ ├── home_button_listener
│ │ │ └── home_button_listener.dart
│ │ ├── logging
│ │ │ └── file_logger.dart
│ │ ├── toast
│ │ │ └── toast_service.dart
│ │ ├── date_changed
│ │ │ └── date_changed_listener.dart
│ │ ├── google_search
│ │ │ └── google_search.dart
│ │ ├── device_locale
│ │ │ └── device_locale_changed_listener.dart
│ │ ├── app_environment
│ │ │ └── app_environment.dart
│ │ ├── platform_methods
│ │ │ └── platform_methods_service.dart
│ │ └── file_system
│ │ │ └── file_system.dart
│ ├── resources
│ │ ├── theme
│ │ │ ├── leafy_theme_constants.dart
│ │ │ └── theme_creators.dart
│ │ ├── assets
│ │ │ └── leafy_icons.dart
│ │ ├── localization
│ │ │ └── l10n_provider.dart
│ │ ├── app_constants.dart
│ │ └── settings
│ │ │ └── vibration_preferences.dart
│ ├── shared_widget
│ │ ├── loader.dart
│ │ ├── section
│ │ │ ├── leafy_section_lib.dart
│ │ │ └── src
│ │ │ │ ├── list
│ │ │ │ └── leafy_section_list_separator.dart
│ │ │ │ ├── items
│ │ │ │ ├── values
│ │ │ │ │ ├── leafy_section_text_value.dart
│ │ │ │ │ └── leafy_section_chevron_value.dart
│ │ │ │ ├── leafy_section_text_item.dart
│ │ │ │ └── leafy_section_custom_item.dart
│ │ │ │ ├── section
│ │ │ │ ├── widget
│ │ │ │ │ ├── leafy_section_footer.dart
│ │ │ │ │ └── leafy_section_header.dart
│ │ │ │ └── leafy_section.dart
│ │ │ │ └── theme
│ │ │ │ └── leafy_section_theme.dart
│ │ ├── themed_state.dart
│ │ ├── themed_widget.dart
│ │ ├── themed_get_widget.dart
│ │ ├── leafy_spacer.dart
│ │ ├── list
│ │ │ ├── dismissible_delete_background.dart
│ │ │ └── list_builder.dart
│ │ └── context_menu
│ │ │ └── context_menu_button.dart
│ ├── applications
│ │ ├── notes
│ │ │ └── leafy_notes_routes.dart
│ │ └── launcher
│ │ │ └── app_routes.dart
│ ├── main.dart
│ └── base
│ │ ├── controller
│ │ └── controller_base.dart
│ │ └── page
│ │ ├── page_base.dart
│ │ └── status_page_base.dart
├── android
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── leafy_icon-playstore.png
│ │ │ │ ├── res
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ ├── leafy_icon.png
│ │ │ │ │ │ └── leafy_icon_round.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ ├── leafy_icon.png
│ │ │ │ │ │ └── leafy_icon_round.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ ├── leafy_icon.png
│ │ │ │ │ │ └── leafy_icon_round.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ ├── leafy_icon.png
│ │ │ │ │ │ └── leafy_icon_round.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ ├── leafy_icon.png
│ │ │ │ │ │ └── leafy_icon_round.png
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── leafy_icon_background.xml
│ │ │ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── drawable
│ │ │ │ │ │ ├── launch_background.xml
│ │ │ │ │ │ ├── splash_background_gradient.xml
│ │ │ │ │ │ └── leafy_notes_launch_background.xml
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ │ ├── launch_background.xml
│ │ │ │ │ │ └── leafy_notes_launch_background.xml
│ │ │ │ │ ├── anim
│ │ │ │ │ │ ├── app_launch_fade_out.xml
│ │ │ │ │ │ ├── app_launch_fade_in.xml
│ │ │ │ │ │ ├── app_launch_fade_in_long.xml
│ │ │ │ │ │ ├── app_launch_fade_out_long.xml
│ │ │ │ │ │ ├── app_launch_left.xml
│ │ │ │ │ │ └── app_launch_right.xml
│ │ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ │ ├── leafy_icon.xml
│ │ │ │ │ │ └── leafy_icon_round.xml
│ │ │ │ │ └── values-night
│ │ │ │ │ │ └── styles.xml
│ │ │ │ └── kotlin
│ │ │ │ │ └── com
│ │ │ │ │ └── nivisi
│ │ │ │ │ └── leafy_launcher
│ │ │ │ │ ├── broadcast_receivers
│ │ │ │ │ ├── DeviceLocaleChangedBroadcastReceiver.kt
│ │ │ │ │ └── AppChangeReceiver.kt
│ │ │ │ │ ├── installed_packages
│ │ │ │ │ └── LauncherAppsCallback.kt
│ │ │ │ │ ├── NotesActivity.kt
│ │ │ │ │ └── LeafyActivityBase.kt
│ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ └── proguard-rules.pro
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── settings.gradle
│ └── build.gradle
├── assets
│ └── icons
│ │ ├── web.svg
│ │ ├── chevron_right.svg
│ │ ├── telegram.svg
│ │ ├── github.svg
│ │ └── gmail.svg
├── .vscode
│ └── launch.json
├── .gitignore
├── pubspec.yaml
└── analysis_options.yaml
├── .github
├── pull_request_template.md
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── ---feature-request.md
│ ├── ---maintenance.md
│ ├── ---custom.md
│ ├── ---localization.md
│ └── ---bug-report.md
└── workflows
│ └── leafy_maintenance_issues.yml
├── .gitignore
└── README.md
/src/lib/utils/app_flavour/app_flavour.dart:
--------------------------------------------------------------------------------
1 | enum AppFlavour {
2 | dev,
3 | prod,
4 | }
5 |
--------------------------------------------------------------------------------
/src/lib/utils/enum/app_launch_transition.dart:
--------------------------------------------------------------------------------
1 | enum AppLaunchTransition {
2 | left,
3 | right,
4 | fade,
5 | }
6 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Resolves #
2 |
3 | ---
4 |
5 | _If needed, leave «what», «why» and «why for» notes here._
6 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/one_to_manys.dart:
--------------------------------------------------------------------------------
1 | library one_to_manys;
2 |
3 | export 'one_to_many/folder_with_notes.dart';
4 |
--------------------------------------------------------------------------------
/src/android/app/src/main/leafy_icon-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/leafy_icon-playstore.png
--------------------------------------------------------------------------------
/src/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | extra-gen-snapshot-options=--obfuscate
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/daos.dart:
--------------------------------------------------------------------------------
1 | library daos;
2 |
3 | export 'models/folder/dao/folder_dao.dart';
4 | export 'models/note/dao/note_dao.dart';
5 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-hdpi/leafy_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-hdpi/leafy_icon.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-mdpi/leafy_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-mdpi/leafy_icon.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xhdpi/leafy_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-xhdpi/leafy_icon.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxhdpi/leafy_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-xxhdpi/leafy_icon.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxxhdpi/leafy_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-xxxhdpi/leafy_icon.png
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models.dart:
--------------------------------------------------------------------------------
1 | library models;
2 |
3 | export 'models/folder/model/folder_model.dart';
4 | export 'models/note/model/note_model.dart';
5 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/tables.dart:
--------------------------------------------------------------------------------
1 | library tables;
2 |
3 | export 'models/folder/table/folder_table.dart';
4 | export 'models/note/table/note_table.dart';
5 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-hdpi/leafy_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-hdpi/leafy_icon_round.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-mdpi/leafy_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-mdpi/leafy_icon_round.png
--------------------------------------------------------------------------------
/src/lib/main_dev.dart:
--------------------------------------------------------------------------------
1 | import 'main.dart';
2 | import 'utils/app_flavour/app_flavour.dart';
3 |
4 | @pragma('vm:entry-point')
5 | void main() => mainCommon(AppFlavour.dev);
6 |
--------------------------------------------------------------------------------
/src/lib/main_prod.dart:
--------------------------------------------------------------------------------
1 | import 'main.dart';
2 | import 'utils/app_flavour/app_flavour.dart';
3 |
4 | @pragma('vm:entry-point')
5 | void main() => mainCommon(AppFlavour.prod);
6 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xhdpi/leafy_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-xhdpi/leafy_icon_round.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxhdpi/leafy_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-xxhdpi/leafy_icon_round.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxxhdpi/leafy_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nivisi/LeafyLauncher/HEAD/src/android/app/src/main/res/mipmap-xxxhdpi/leafy_icon_round.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/leafy_icon_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1B2137
4 |
--------------------------------------------------------------------------------
/src/lib/module/intro/tutorial/domain/slide_type.dart:
--------------------------------------------------------------------------------
1 | enum SlideType {
2 | quickLaunch,
3 | horizontalSwipes,
4 | cornerButtons,
5 | appPicker,
6 | search,
7 | settings,
8 | }
9 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1B2137
4 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/repositories/repositories.dart:
--------------------------------------------------------------------------------
1 | library repositories;
2 |
3 | export '../models/folder/repository/folder_repository.dart';
4 | export '../models/note/repository/note_repository.dart';
5 |
--------------------------------------------------------------------------------
/src/lib/services/applications/application.dart:
--------------------------------------------------------------------------------
1 | abstract class Application {
2 | const Application({
3 | required this.name,
4 | required this.package,
5 | });
6 |
7 | final String name;
8 | final String package;
9 | }
10 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/lib/module/home/home_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_controller.dart';
4 |
5 | class HomeBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.put(HomeController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/services/device_vibration/device_vibration.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class DeviceVibration {
4 | const DeviceVibration();
5 |
6 | Future weak() async {
7 | return HapticFeedback.selectionClick();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/resources/theme/leafy_theme_constants.dart:
--------------------------------------------------------------------------------
1 | const kBodyText1FontSize = 30.0;
2 | const kBodyText2FontSize = 24.0;
3 | const kBodyText3FontSize = 20.0;
4 | const kBodyText4FontSize = 16.0;
5 | const kBodyText5FontSize = 18.0;
6 | const kBodyText6FontSize = 13.0;
7 |
--------------------------------------------------------------------------------
/src/lib/services/applications/leafy_application.dart:
--------------------------------------------------------------------------------
1 | import 'application.dart';
2 |
3 | class LeafyApplication extends Application {
4 | const LeafyApplication({
5 | required String name,
6 | required String package,
7 | }) : super(name: name, package: package);
8 | }
9 |
--------------------------------------------------------------------------------
/src/lib/module/startup/startup_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'startup_controller.dart';
4 |
5 | class StartupBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => StartupController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/services/applications/exceptions/app_is_not_in_the_list_exception.dart:
--------------------------------------------------------------------------------
1 | class AppIsNotInTheListException implements Exception {
2 | const AppIsNotInTheListException({
3 | this.message = 'App was already removed from the list',
4 | });
5 |
6 | final String message;
7 | }
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: 📑 Contribution Guidelines
4 | url: https://github.com/nivisi/LeafyLauncher/wiki/Contribution-Guidelines#issues
5 | about: Please check out contribution guidelines before opening an issue.
6 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/one_to_many/folder_with_notes.dart:
--------------------------------------------------------------------------------
1 | import '../../leafy_notes_database.dart';
2 |
3 | class FolderWithNotes {
4 | FolderWithNotes({required this.folder, required this.notes});
5 |
6 | final FolderModel folder;
7 | final List notes;
8 | }
9 |
--------------------------------------------------------------------------------
/src/lib/services/applications/exceptions/unable_to_uninstall_a_system_app_exception.dart:
--------------------------------------------------------------------------------
1 | class UninstallSystemAppException implements Exception {
2 | const UninstallSystemAppException({
3 | this.message = 'Unable to uninstall a system app',
4 | });
5 |
6 | final String message;
7 | }
8 |
--------------------------------------------------------------------------------
/src/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 09 19:39:40 EET 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/loader.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Loader extends StatelessWidget {
4 | const Loader({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const CircularProgressIndicator();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/module/home_notes/notes/folders/home_note_folders_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_note_folders_controller.dart';
4 |
5 | class HomeNoteFoldersBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.put(HomeNoteFoldersController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/anim/app_launch_fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/anim/app_launch_fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-anydpi-v26/leafy_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/home_settings_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_settings_controller.dart';
4 |
5 | class HomeSettingsBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => HomeSettingsController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/anim/app_launch_fade_in_long.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/anim/app_launch_fade_out_long.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-anydpi-v26/leafy_icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/lib/module/home/widget/corner_button/_full_screen_box.dart:
--------------------------------------------------------------------------------
1 | part of 'corner_button.dart';
2 |
3 | class _FullScreenBox extends StatelessWidget {
4 | const _FullScreenBox({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Container(color: Colors.transparent);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/drawable/splash_background_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/leafy_section_lib.dart:
--------------------------------------------------------------------------------
1 | library leafy_section;
2 |
3 | export 'src/items/leafy_section_custom_item.dart';
4 | export 'src/items/leafy_section_text_item.dart';
5 | export 'src/items/values/leafy_section_chevron_value.dart';
6 | export 'src/items/values/leafy_section_text_value.dart';
7 | export 'src/section/leafy_section.dart';
8 |
--------------------------------------------------------------------------------
/src/lib/services/applications/installed_application.dart:
--------------------------------------------------------------------------------
1 | import 'application.dart';
2 |
3 | class InstalledApplication extends Application {
4 | const InstalledApplication({
5 | required String name,
6 | required String package,
7 | required this.isSystem,
8 | }) : super(name: name, package: package);
9 |
10 | final bool isSystem;
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/resources/assets/leafy_icons.dart:
--------------------------------------------------------------------------------
1 | class LeafyIcons {
2 | static const _path = 'assets/icons';
3 |
4 | static const chevronRight = '$_path/chevron_right.svg';
5 | static const github = '$_path/github.svg';
6 | static const gmail = '$_path/gmail.svg';
7 | static const telegram = '$_path/telegram.svg';
8 | static const web = '$_path/web.svg';
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/note/table/sorts.dart:
--------------------------------------------------------------------------------
1 | part of '../dao/note_dao.dart';
2 |
3 | OrderingTerm _notesByLastEditedAt($NotesTable table) {
4 | return OrderingTerm.desc(table.lastEditedAt);
5 | }
6 |
7 | // OrderingTerm _notesByTitleOrFirstLine($NotesTable table) {
8 | // return OrderingTerm.asc(coalesce([table.title, table.firstLine]));
9 | // }
10 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss/home_settings_oss_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_settings_oss_controller.dart';
4 |
5 | class HomeSettingsOssBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => HomeSettingsOssController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/home_settings_about_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_settings_about_controller.dart';
4 |
5 | class HomeSettingsAboutBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => HomeSettingsAboutController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/lib/services/oss_licenses/oss_license.dart:
--------------------------------------------------------------------------------
1 | class OssLicense {
2 | OssLicense({
3 | required this.name,
4 | required this.version,
5 | this.description,
6 | required this.license,
7 | this.homepage,
8 | });
9 |
10 | final String name;
11 | final String version;
12 | final String? description;
13 | final String license;
14 | final String? homepage;
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widgets/home_settings_widgets_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_settings_widgets_controller.dart';
4 |
5 | class HomeSettingsWidgetsBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => HomeSettingsWidgetsController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/services/share/share_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:share/share.dart';
4 |
5 | class ShareService {
6 | Future shareText(String text, {String? subject}) {
7 | return Share.share(text, subject: subject);
8 | }
9 |
10 | Future shareFile(File file, {String? subject}) {
11 | return Share.shareFiles([file.path], subject: subject);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/lib/utils/log/logable_mixin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:logger/logger.dart';
3 |
4 | import 'get_logger.dart';
5 |
6 | mixin LogableMixin {
7 | Logger? _logger;
8 |
9 | @protected
10 | Logger get logger => _logger ??= getLogger(forObject: this);
11 |
12 | @override
13 | String toString() {
14 | return runtimeType.toString();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/utils/extensions/iterable_extensions.dart:
--------------------------------------------------------------------------------
1 | extension IterableExtensions on Iterable {
2 | T? firstOrNull() {
3 | if (length > 0) {
4 | return first;
5 | }
6 |
7 | return null;
8 | }
9 |
10 | T? firstWhereOrNull(bool Function(T item) condition) {
11 | if (length > 0) {
12 | return firstWhere(condition);
13 | }
14 |
15 | return null;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/extensions/iterable_extensions.dart:
--------------------------------------------------------------------------------
1 | extension IterableExtensions on Iterable {
2 | T? firstOrNull() {
3 | if (length > 0) {
4 | return first;
5 | }
6 |
7 | return null;
8 | }
9 |
10 | T? firstWhereOrNull(bool Function(T item) condition) {
11 | if (length > 0) {
12 | return firstWhere(condition);
13 | }
14 |
15 | return null;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/module/intro/tutorial/tutorial_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:leafy_launcher/module/home_settings/home_settings_controller.dart';
3 |
4 | import 'tutorial_controller.dart';
5 |
6 | class TutorialBinding implements Bindings {
7 | @override
8 | void dependencies() {
9 | Get.lazyPut(() => TutorialController());
10 | Get.lazyPut(() => HomeSettingsController());
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/drawable-v21/leafy_notes_launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
5 |
6 |
7 | -
10 |
11 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/drawable/leafy_notes_launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
5 |
6 |
7 | -
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/module/intro/intro_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:leafy_launcher/module/home_settings/home_settings_controller.dart';
3 | import 'package:leafy_launcher/module/intro/intro_controller.dart';
4 |
5 | class IntroBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => IntroController());
9 | Get.lazyPut(() => HomeSettingsController());
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/assets/icons/web.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/note/repository/note_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../../models.dart';
2 | import '../../../one_to_manys.dart';
3 |
4 | abstract class NoteRepository {
5 | Stream watchAllNotesOfFolder(String id);
6 |
7 | Future getById(String id);
8 | Future create(FolderModel folder);
9 | Future update(NoteModel folder);
10 | Future delete(NoteModel folder);
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/module/home_notes/notes/notes/home_notes_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_notes_controller.dart';
4 |
5 | class HomeNotesBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | final folderId = Get.parameters['folderId'];
9 |
10 | if (folderId is! String) {
11 | throw Exception('folderId is not found');
12 | }
13 |
14 | Get.put(HomeNotesController(folderId));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | ## Flutter wrapper
2 | -keep class io.flutter.app.** { *; }
3 | -keep class io.flutter.plugin.** { *; }
4 | -keep class io.flutter.util.** { *; }
5 | -keep class io.flutter.view.** { *; }
6 | -keep class io.flutter.** { *; }
7 | -keep class io.flutter.plugins.** { *; }
8 | # -keep class com.google.firebase.** { *; } // uncomment this if you are using firebase in the project
9 | -dontwarn io.flutter.embedding.**
10 | -ignorewarnings
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/extensions/map_extensions.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: avoid_catching_errors
2 |
3 | extension MapExtensions on Map {
4 | TValue? firstWhereKeyOrNull(bool Function(TKey item) condition) {
5 | if (keys.isNotEmpty) {
6 | try {
7 | final key = keys.firstWhere(condition);
8 |
9 | return this[key];
10 | } on Error {
11 | return null;
12 | }
13 | }
14 |
15 | return null;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/note/dao/note_dao.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'note_dao.dart';
4 |
5 | // **************************************************************************
6 | // DaoGenerator
7 | // **************************************************************************
8 |
9 | mixin _$NoteDaoMixin on DatabaseAccessor {
10 | $NotesTable get notes => attachedDatabase.notes;
11 | $FoldersTable get folders => attachedDatabase.folders;
12 | }
13 |
--------------------------------------------------------------------------------
/src/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/folder/dao/folder_dao.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'folder_dao.dart';
4 |
5 | // **************************************************************************
6 | // DaoGenerator
7 | // **************************************************************************
8 |
9 | mixin _$FolderDaoMixin on DatabaseAccessor {
10 | $NotesTable get notes => attachedDatabase.notes;
11 | $FoldersTable get folders => attachedDatabase.folders;
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/body/oss/oss.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_about_body.dart';
2 |
3 | class _Oss extends ThemedGetWidget {
4 | const _Oss({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget body(BuildContext context, LeafyTheme theme) {
8 | return LeafySectionTextItem(
9 | title: L10nProvider.getText(L10n.settingsAboutOss),
10 | onTap: controller.openOss,
11 | value: const LeafySectionChevronValue(),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/about/about.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_body.dart';
2 |
3 | class _About extends ThemedGetWidget {
4 | const _About({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget body(BuildContext context, LeafyTheme theme) {
8 | return LeafySectionTextItem(
9 | title: L10nProvider.getText(L10n.settingsAbout),
10 | onTap: controller.openAbout,
11 | value: const LeafySectionChevronValue(),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/icons/chevron_right.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/lib/resources/theme/theme_creators.dart:
--------------------------------------------------------------------------------
1 | part of 'leafy_theme.dart';
2 |
3 | typedef ThemeCreator = S Function({
4 | required Widget child,
5 | });
6 |
7 | HomeTheme _homeCreator(Widget child) {
8 | switch (LeafyTheme.currentStyle) {
9 | case LeafyThemeStyle.light:
10 | return HomeTheme.light(child);
11 | case LeafyThemeStyle.dark:
12 | return HomeTheme.dark(child);
13 | default:
14 | throw 'Unknown style';
15 | }
16 | }
17 |
18 | final _creatorMap = {
19 | HomeTheme: _homeCreator,
20 | };
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F9E9 Feature request"
3 | about: Suggest a feature for Leafy
4 | title: ''
5 | labels: feature
6 | assignees: ''
7 |
8 | ---
9 |
10 |
17 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss_license/home_settings_oss_license_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_settings_oss_license_controller.dart';
4 |
5 | class HomeSettingsOssLicenseBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | final name = Get.parameters['name'];
9 |
10 | if (name is! String) {
11 | throw Exception('name is not found');
12 | }
13 |
14 | Get.lazyPut(
15 | () => HomeSettingsOssLicenseController(name),
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/common/theme.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_body.dart';
2 |
3 | class _Theme extends ThemedGetWidget {
4 | const _Theme({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget body(BuildContext context, LeafyTheme theme) {
8 | return LeafySectionTextItem(
9 | title: L10nProvider.getText(L10n.settingsTheme),
10 | onTap: controller.changeTheme,
11 | value: LeafySectionTextValue(value: theme.style.localize()),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.github/workflows/leafy_maintenance_issues.yml:
--------------------------------------------------------------------------------
1 | name: 🔧 Move Maintenance issues to Maintenance project
2 |
3 | on:
4 | issues:
5 | types:
6 | - labeled
7 |
8 | env:
9 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10 |
11 | jobs:
12 | AssignMaintenanceProject:
13 | runs-on: ubuntu-latest
14 | if: github.event.label.name == 'maintenance'
15 | steps:
16 | - name: Assign to Maintenance Project
17 | uses: srggrs/assign-one-project-github-action@1.2.1
18 | with:
19 | project: 'https://github.com/nivisi/LeafyLauncher/projects/8'
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---maintenance.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F9F9 Maintenance"
3 | about: Suggest codebase improvements (refactoring, naming etc)
4 | title: ''
5 | labels: maintenance
6 | assignees: ''
7 |
8 | ---
9 |
10 |
17 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/folder/table/sorts.dart:
--------------------------------------------------------------------------------
1 | part of '../dao/folder_dao.dart';
2 |
3 | OrderingTerm _foldersByIsDefault($FoldersTable table) {
4 | return OrderingTerm(
5 | expression: table.isDefault,
6 | mode: OrderingMode.desc,
7 | );
8 | }
9 |
10 | OrderingTerm _foldersByLastEditedAt($FoldersTable table) {
11 | return OrderingTerm(
12 | expression: table.lastEditedAt,
13 | mode: OrderingMode.desc,
14 | );
15 | }
16 |
17 | // OrderingTerm _foldersByTitle($FoldersTable table) {
18 | // return OrderingTerm(expression: table.title);
19 | // }
20 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/anim/app_launch_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F3A8 Custom"
3 | about: Provide some feedback or a report, probably not related to the Android Application
4 | codebase
5 | title: ''
6 | labels: ''
7 | assignees: ''
8 |
9 | ---
10 |
11 |
18 |
--------------------------------------------------------------------------------
/src/lib/module/app_picker/app_picker_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../../services/applications/application.dart';
4 | import '../../utils/enum/user_selected_app_type.dart';
5 | import 'app_picker_controller_base.dart';
6 |
7 | class AppPickerController extends AppPickerControllerBase {
8 | AppPickerController({
9 | bool selectOnFirstMatch = false,
10 | UserSelectedAppType? type,
11 | }) : super(selectOnFirstMatch: selectOnFirstMatch, type: type);
12 |
13 | @override
14 | Future onAppSelected(Application app) async {
15 | Get.back(result: app);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/body/info/gmail.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_about_body.dart';
2 |
3 | class _Gmail extends ThemedGetWidget {
4 | const _Gmail({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget body(BuildContext context, LeafyTheme theme) {
8 | return LeafySectionTextItem(
9 | title: L10nProvider.getText(L10n.settingsAboutOpenGmail),
10 | leading: SvgPicture.asset(
11 | LeafyIcons.gmail,
12 | color: theme.foregroundColor,
13 | ),
14 | onTap: controller.openGmail,
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/folder/repository/folder_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../../models.dart';
2 | import '../../../one_to_manys.dart';
3 |
4 | abstract class FolderRepository {
5 | FolderModel get defaultFolder;
6 |
7 | Stream> watchAllFolderWithNotes();
8 |
9 | Future getById(String id);
10 | Future create({String? withTitle});
11 |
12 | Future insert(FolderModel model);
13 | Future update(FolderModel model);
14 | Future delete(FolderModel model);
15 |
16 | Stream watchFolder(String folderId);
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/module/home/widget/home_widgets/home_top_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
3 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
4 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
5 |
6 | class HomeTopWidget extends ThemedWidget {
7 | const HomeTopWidget({Key? key}) : super(key: key);
8 |
9 | @override
10 | Widget body(BuildContext context, LeafyTheme theme) {
11 | return Icon(
12 | Icons.search,
13 | color: theme.foregroundColor,
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/body/info/github.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_about_body.dart';
2 |
3 | class _GitHub extends ThemedGetWidget {
4 | const _GitHub({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget body(BuildContext context, LeafyTheme theme) {
8 | return LeafySectionTextItem(
9 | title: L10nProvider.getText(L10n.settingsAboutOpenGithub),
10 | leading: SvgPicture.asset(
11 | LeafyIcons.github,
12 | color: theme.foregroundColor,
13 | ),
14 | onTap: controller.openGithub,
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/services/home_button_listener/home_button_listener.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 |
6 | class HomeButtonListener {
7 | const HomeButtonListener();
8 |
9 | static const _channel = EventChannel(
10 | 'com.nivisi.leafy_launcher/homePressedChannel',
11 | );
12 |
13 | static final Stream _stream = _channel.receiveBroadcastStream();
14 |
15 | StreamSubscription addCallback(VoidCallback callback) {
16 | return _stream.listen(
17 | (_) {
18 | callback();
19 | },
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/utils/log/pretty_console_output.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:logger/logger.dart';
3 |
4 | class PrettyConsoleOutput extends ConsoleOutput {
5 | static final levelEmojis = {
6 | Level.verbose: '',
7 | Level.debug: '🐛 ',
8 | Level.info: '💡 ',
9 | Level.warning: '⚠️ ',
10 | Level.error: '⛔ ',
11 | Level.wtf: '👾 ',
12 | };
13 |
14 | @override
15 | void output(OutputEvent event) {
16 | for (var i = 0; i < event.lines.length; i++) {
17 | debugPrint('${i == 0 ? levelEmojis[event.level] : ''}${event.lines[i]}');
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/module/intro/intro_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/base/page/page_base.dart';
3 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
4 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
5 |
6 | import 'intro_controller.dart';
7 | import 'widget/hello_and_welcome.dart';
8 |
9 | class IntroPage extends PageBase {
10 | const IntroPage({Key? key}) : super(key: key);
11 |
12 | @override
13 | Widget pageBody(BuildContext context, LeafyTheme theme) {
14 | return const HelloAndWelcome();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/anim/app_launch_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/body/info/telegram.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_about_body.dart';
2 |
3 | class _Telegram
4 | extends ThemedGetWidget {
5 | const _Telegram({Key? key}) : super(key: key);
6 |
7 | @override
8 | Widget body(BuildContext context, LeafyTheme theme) {
9 | return LeafySectionTextItem(
10 | title: L10nProvider.getText(L10n.settingsAboutOpenTelegram),
11 | leading: SvgPicture.asset(
12 | LeafyIcons.telegram,
13 | color: theme.foregroundColor,
14 | ),
15 | onTap: controller.openTelegram,
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---localization.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F3AD Localization"
3 | about: Request a new language translation or report an incorrect or unclear translations
4 | title: ''
5 | labels: l10n
6 | assignees: ''
7 |
8 | ---
9 |
10 |
17 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/list/leafy_section_list_separator.dart:
--------------------------------------------------------------------------------
1 | part of 'leafy_section_list.dart';
2 |
3 | class _LeafySectionListSeparator
4 | extends ThemedWidget {
5 | const _LeafySectionListSeparator({Key? key}) : super(key: key);
6 |
7 | @override
8 | Widget body(BuildContext context, LeafyTheme theme) {
9 | return Padding(
10 | padding: const EdgeInsets.only(
11 | top: kDefaultPadding * 2.0,
12 | bottom: kDefaultPadding * 2.0,
13 | ),
14 | child: Divider(
15 | height: 1.0,
16 | color: theme.separatorColor,
17 | ),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/services/logging/file_logger.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:get/get.dart';
4 | import 'package:intl/intl.dart';
5 |
6 | import '../file_system/file_system.dart';
7 |
8 | class FileLogger {
9 | final _fileSystem = Get.find();
10 | final _dateFormatter = DateFormat('dd.MM.yyyy');
11 |
12 | File getFileForToday() {
13 | final today = DateTime.now();
14 | final fileName =
15 | '''${_fileSystem.loggingDirectory.path}/log${_dateFormatter.format(today)}.log''';
16 | final file = File(fileName);
17 | if (!file.existsSync()) {
18 | file.createSync();
19 | }
20 | return file;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/module/home/utils/gesture_processer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | enum Direction { left, right, up, down }
4 |
5 | class GestureProcessor {
6 | Offset? startPoint;
7 | Offset? endPoint;
8 |
9 | Direction end() {
10 | if (startPoint == null || endPoint == null) {
11 | throw Exception('Both startPoint and endPoint must be configured');
12 | }
13 |
14 | final dx = startPoint!.dx - endPoint!.dx;
15 | final dy = startPoint!.dy - endPoint!.dy;
16 | if (dx.abs() > dy.abs()) {
17 | return dx < 0 ? Direction.right : Direction.left;
18 | }
19 | return dy < 0 ? Direction.down : Direction.up;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/module/intro/tutorial/tutorial_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/base/page/page_base.dart';
3 | import 'package:leafy_launcher/module/intro/tutorial/widget/tutorial.dart';
4 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
5 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
6 |
7 | import 'tutorial_controller.dart';
8 |
9 | class TutorialPage extends PageBase {
10 | const TutorialPage({Key? key}) : super(key: key);
11 |
12 | @override
13 | Widget pageBody(BuildContext context, LeafyTheme theme) {
14 | return const Tutorial();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/utils/log/get_logger.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:logger/logger.dart';
3 |
4 | import 'file_output.dart' as file_output;
5 | import 'pretty_console_output.dart';
6 | import 'simple_log_printer.dart';
7 |
8 | file_output.FileOutput _fileOutput = file_output.FileOutput();
9 | PrettyConsoleOutput _prettyConsoleOutput = PrettyConsoleOutput();
10 |
11 | Logger getLogger({dynamic forObject}) {
12 | return Logger(
13 | printer: SimpleLogPrinter(forObject: forObject),
14 | output: MultiOutput([_fileOutput, _prettyConsoleOutput]),
15 | filter: ProductionFilter(),
16 | level: kDebugMode ? Level.verbose : Level.info,
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/items/values/leafy_section_text_value.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
3 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
4 |
5 | class LeafySectionTextValue
6 | extends ThemedWidget {
7 | const LeafySectionTextValue({
8 | Key? key,
9 | required this.value,
10 | }) : super(key: key);
11 |
12 | final String value;
13 |
14 | @override
15 | Widget body(BuildContext context, LeafyTheme theme) {
16 | return Text(
17 | value,
18 | style: theme.bodyText4.copyWith(color: theme.textInfoColor),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.3.0-alpha01'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/leafy_notes_db.dart:
--------------------------------------------------------------------------------
1 | import 'package:moor_flutter/moor_flutter.dart';
2 |
3 | import 'daos.dart';
4 | import 'tables.dart';
5 |
6 | part 'leafy_notes_db.g.dart';
7 |
8 | // ignore: non_constant_identifier_names
9 | final LeafyNotesDb = LeafyNotesDatabase();
10 |
11 | @UseMoor(
12 | tables: [Notes, Folders],
13 | daos: [NoteDao, FolderDao],
14 | )
15 | class LeafyNotesDatabase extends _$LeafyNotesDatabase {
16 | LeafyNotesDatabase()
17 | : super(
18 | FlutterQueryExecutor.inDatabaseFolder(
19 | path: 'leafy_notes.sqlite',
20 | logStatements: true,
21 | ),
22 | );
23 |
24 | @override
25 | int get schemaVersion => 1;
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/module/home_notes/notes/note/home_note_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'home_note_controller.dart';
4 |
5 | class HomeNoteBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | final folderId = Get.parameters['folderId'];
9 |
10 | if (folderId is! String) {
11 | throw Exception('folderId is not found');
12 | }
13 |
14 | final noteId = Get.parameters['noteId'];
15 |
16 | if (noteId is! String) {
17 | throw Exception('noteId is not found');
18 | }
19 |
20 | Get.lazyPut(
21 | () => HomeNoteController(
22 | folderId: folderId,
23 | noteId: noteId,
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/lib/services/toast/toast_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:fluttertoast/fluttertoast.dart';
2 |
3 | class ToastService {
4 | const ToastService();
5 |
6 | Future short(String text, {bool cancelPrevious = false}) async {
7 | if (cancelPrevious) {
8 | await Fluttertoast.cancel();
9 | }
10 |
11 | await Fluttertoast.showToast(
12 | msg: text,
13 | toastLength: Toast.LENGTH_SHORT,
14 | );
15 | }
16 |
17 | Future long(String text, {bool cancelPrevious = false}) async {
18 | if (cancelPrevious) {
19 | await Fluttertoast.cancel();
20 | }
21 |
22 | await Fluttertoast.showToast(
23 | msg: text,
24 | toastLength: Toast.LENGTH_LONG,
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41B Bug report"
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
19 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/section/widget/leafy_section_footer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
3 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
4 |
5 | class LeafySectionFooter
6 | extends ThemedWidget {
7 | const LeafySectionFooter({
8 | Key? key,
9 | required this.title,
10 | }) : super(key: key);
11 |
12 | final String title;
13 |
14 | @override
15 | Widget body(BuildContext context, LeafyTheme theme) {
16 | return Text(
17 | title,
18 | style: theme.bodyText6.copyWith(
19 | color: theme.textInfoColor,
20 | ),
21 | textAlign: TextAlign.start,
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/items/values/leafy_section_chevron_value.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_svg/flutter_svg.dart';
3 | import 'package:leafy_launcher/resources/assets/leafy_icons.dart';
4 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
5 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
6 |
7 | class LeafySectionChevronValue
8 | extends ThemedWidget {
9 | const LeafySectionChevronValue({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget body(BuildContext context, LeafyTheme theme) {
13 | return SvgPicture.asset(
14 | LeafyIcons.chevronRight,
15 | color: theme.textInfoColor,
16 | height: 12,
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/applications/notes/leafy_notes_routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class LeafyNotesRoutes {
4 | static const notes = '/folders/:folderId/notes';
5 | static const note = '/folders/:folderId/notes/:noteId';
6 | static const folders = '/folders';
7 |
8 | static Future? toFolders() {
9 | return Get.toNamed(folders);
10 | }
11 |
12 | static Future? toNotes(String folderId) {
13 | final route = notes.replaceFirst(':folderId', folderId);
14 |
15 | return Get.toNamed(route);
16 | }
17 |
18 | static Future? toNote(String folderId, String noteId) {
19 | final route = note
20 | .replaceFirst(':folderId', folderId)
21 | .replaceFirst(':noteId', noteId);
22 |
23 | return Get.toNamed(route);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/module/startup/startup_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../../base/page/status_page_base.dart';
4 | import '../../resources/theme/home_theme.dart';
5 | import '../../resources/theme/leafy_theme.dart';
6 | import 'startup_controller.dart';
7 |
8 | class StartupPage extends StatusPageBase {
9 | const StartupPage();
10 |
11 | @override
12 | Widget loading(BuildContext context, LeafyTheme theme) {
13 | return Center(
14 | child: Text(
15 | 'Loading applications ...',
16 | style: theme.bodyText3,
17 | ),
18 | );
19 | }
20 |
21 | @override
22 | Widget ready(BuildContext context, LeafyTheme theme) {
23 | return const Center(child: Text('Im the startup page'));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/services/date_changed/date_changed_listener.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | class DateChangedListener {
4 | DateChangedListener() {
5 | init();
6 | }
7 |
8 | late Timer _timer;
9 |
10 | DateTime _lastKnownDate = DateTime.now();
11 |
12 | final _controller = StreamController.broadcast();
13 | Stream get onDateChanged => _controller.stream;
14 |
15 | void init() {
16 | _timer = Timer.periodic(
17 | const Duration(seconds: 1),
18 | (timer) {
19 | final now = DateTime.now();
20 |
21 | if (_lastKnownDate.day != now.day) {
22 | _controller.add(null);
23 | }
24 |
25 | _lastKnownDate = now;
26 | },
27 | );
28 | }
29 |
30 | void dispose() {
31 | _timer.cancel();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/section/widget/leafy_section_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
3 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
4 |
5 | class LeafySectionHeader
6 | extends ThemedWidget {
7 | const LeafySectionHeader({
8 | Key? key,
9 | required this.title,
10 | }) : super(key: key);
11 |
12 | final String title;
13 |
14 | @override
15 | Widget body(BuildContext context, LeafyTheme theme) {
16 | return Text(
17 | title.toUpperCase(),
18 | style: theme.bodyText6.copyWith(
19 | color: theme.textInfoColor,
20 | ),
21 | textAlign: TextAlign.start,
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/utils/log/file_output.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:get/get.dart';
5 | import 'package:logger/logger.dart';
6 | import 'package:synchronized/synchronized.dart';
7 |
8 | import '../../services/logging/file_logger.dart';
9 |
10 | class FileOutput extends LogOutput {
11 | final _fileLogService = Get.find();
12 |
13 | final _lock = Lock();
14 |
15 | Future write(OutputEvent event) {
16 | final file = _fileLogService.getFileForToday();
17 | return file.writeAsString(
18 | '${event.lines.join('\n')}\n',
19 | mode: FileMode.append,
20 | );
21 | }
22 |
23 | @override
24 | void output(OutputEvent event) {
25 | _lock.synchronized(() {
26 | return write(event);
27 | });
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/lib/utils/app_goes_to_background_aware/app_goes_to_background_aware.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AppGoesToBackgroundListener extends WidgetsBindingObserver {
4 | AppGoesToBackgroundListener(this._onGoesToBackground) {
5 | WidgetsBinding.instance!.addObserver(this);
6 | }
7 |
8 | bool _disposed = false;
9 | VoidCallback? _onGoesToBackground;
10 |
11 | @override
12 | void didChangeAppLifecycleState(AppLifecycleState state) {
13 | if (!_disposed && state == AppLifecycleState.paused) {
14 | _onGoesToBackground?.call();
15 | }
16 | }
17 |
18 | void dispose() {
19 | if (!_disposed) {
20 | WidgetsBinding.instance!.removeObserver(this);
21 | _disposed = true;
22 | _onGoesToBackground = null;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/services/google_search/google_search.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 | import '../../utils/log/logable_mixin.dart';
3 |
4 | class GoogleSearch with LogableMixin {
5 | static const _channel = MethodChannel('com.nivisi.leafy_launcher/common');
6 |
7 | Future launchSearchAndroid(String query) async {
8 | try {
9 | await _channel.invokeMethod(
10 | 'launchSearch',
11 | {'launchQuery': query},
12 | );
13 | } on Exception catch (e) {
14 | logger.e('Unable to launch search', e);
15 | }
16 | }
17 |
18 | Future openGoogleInput() async {
19 | try {
20 | await _channel.invokeMethod('launchGoogleSearchInput');
21 | } on Exception catch (e) {
22 | logger.e('Unable to launch google search input', e);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/folder/model/folder_converter.dart:
--------------------------------------------------------------------------------
1 | import '../../../leafy_notes_db.dart';
2 | import 'folder_model.dart';
3 |
4 | Folder folderModelToDb(FolderModel folder) {
5 | return Folder(
6 | id: folder.id,
7 | title: folder.title,
8 | lastEditedAt: folder.lastEditedAt,
9 | createdAt: folder.createdAt,
10 | isDefault: folder.isDefault,
11 | isArchived: folder.isArchived,
12 | isPinned: folder.isPinned,
13 | );
14 | }
15 |
16 | FolderModel folderModelFromDb(Folder folder) {
17 | return FolderModel(
18 | id: folder.id,
19 | title: folder.title,
20 | lastEditedAt: folder.lastEditedAt,
21 | createdAt: folder.createdAt,
22 | isDefault: folder.isDefault,
23 | isArchived: folder.isArchived,
24 | isPinned: folder.isPinned,
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/folder/table/folder_table.dart:
--------------------------------------------------------------------------------
1 | import 'package:moor_flutter/moor_flutter.dart';
2 |
3 | @DataClassName('Folder')
4 | class Folders extends Table {
5 | TextColumn get id => text()();
6 | TextColumn get title =>
7 | text().withLength(min: 1, max: 255).withDefault(const Constant(''))();
8 | DateTimeColumn get createdAt => dateTime()();
9 | DateTimeColumn get lastEditedAt => dateTime()();
10 | // TODO: Set a constraint that there can be only 1 default folder.
11 | BoolColumn get isDefault => boolean().withDefault(const Constant(false))();
12 | BoolColumn get isArchived => boolean().withDefault(const Constant(false))();
13 | BoolColumn get isPinned => boolean().withDefault(const Constant(false))();
14 |
15 | @override
16 | Set? get primaryKey => {id};
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/resources/localization/l10n_provider.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:get/get.dart';
4 |
5 | import 'l10n.dart';
6 |
7 | part 'l10n_provider_map_en_us.dart';
8 | part 'l10n_provider_map_ru_ru.dart';
9 | part 'l10n_provider_map_fr_fr.dart';
10 |
11 | class L10nProvider extends Translations {
12 | static String getText(String key) {
13 | final localizedString = key.tr;
14 |
15 | return localizedString == key ? 'UNKNOWN: $key' : localizedString;
16 | }
17 |
18 | String _getKey(Locale locale) {
19 | return '${locale.languageCode}_${locale.countryCode}';
20 | }
21 |
22 | @override
23 | Map> get keys => {
24 | _getKey(L10n.enLocale): _mapEn,
25 | _getKey(L10n.ruLocale): _mapRu,
26 | _getKey(L10n.frLocale): _mapFr,
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/common/language.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_body.dart';
2 |
3 | class _Language extends ThemedGetWidget {
4 | const _Language({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget body(BuildContext context, LeafyTheme theme) {
8 | return LeafySectionTextItem(
9 | title: L10nProvider.getText(L10n.settingsLanguage),
10 | onTap: controller.changeLocale,
11 | value: GetBuilder(
12 | id: UserApplicationsController.kLanguageBuilder,
13 | init: controller,
14 | builder: (_) {
15 | return LeafySectionTextValue(
16 | value: controller.getLanguageTitle(),
17 | );
18 | },
19 | ),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss_license/title/home_settings_oss_license_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
3 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
4 | import 'package:leafy_launcher/shared_widget/page/page_header.dart';
5 | import 'package:leafy_launcher/shared_widget/themed_get_widget.dart';
6 |
7 | import '../home_settings_oss_license_controller.dart';
8 |
9 | class SettingsOssLicenseTitle
10 | extends ThemedGetWidget {
11 | const SettingsOssLicenseTitle({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget body(BuildContext context, LeafyTheme theme) {
15 | return PageHeader(
16 | title: controller.title,
17 | onTapped: controller.onTitleTapped,
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/themed_state.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import '../resources/theme/leafy_theme.dart';
4 |
5 | abstract class ThemedState extends State {
7 | @override
8 | @nonVirtual
9 | Widget build(BuildContext context) {
10 | final theme = context.dependOnInheritedWidgetOfExactType();
11 |
12 | assert(theme != null);
13 |
14 | if (theme == null) {
15 | return const ColoredBox(
16 | color: Colors.red,
17 | child: Padding(
18 | padding: EdgeInsets.all(8.0),
19 | child: Text('THEME NOT FOUND!'),
20 | ),
21 | );
22 | }
23 |
24 | return body(context, theme);
25 | }
26 |
27 | Widget body(BuildContext context, TTheme theme);
28 | }
29 |
--------------------------------------------------------------------------------
/src/android/app/src/main/kotlin/com/nivisi/leafy_launcher/broadcast_receivers/DeviceLocaleChangedBroadcastReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.nivisi.leafy_launcher.broadcast_receivers
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import com.nivisi.leafy_launcher.MainActivity
7 | import com.nivisi.leafy_launcher.NotesActivity
8 | import java.util.*
9 |
10 | class DeviceLocaleChangedBroadcastReceiver : BroadcastReceiver() {
11 | override fun onReceive(context: Context?, intent: Intent?) {
12 | if (intent?.action == Intent.ACTION_LOCALE_CHANGED) {
13 | val languageTag = Locale.getDefault().toLanguageTag()
14 | MainActivity.self?.dispatchDeviceLocaleChangedEvent(languageTag)
15 | NotesActivity.self?.dispatchDeviceLocaleChangedEvent(languageTag)
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss/home_settings_oss_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../../../base/page/status_page_base.dart';
4 | import '../../../resources/theme/home_theme.dart';
5 | import '../../../resources/theme/leafy_theme.dart';
6 | import 'body/settings_oss_body.dart';
7 | import 'home_settings_oss_controller.dart';
8 | import 'title/home_settings_oss_title.dart';
9 |
10 | class HomeSettingsOssPage
11 | extends StatusPageBase {
12 | const HomeSettingsOssPage();
13 |
14 | @override
15 | bool get resizeToAvoidBottomInset => false;
16 |
17 | @override
18 | Widget ready(BuildContext context, LeafyTheme theme) {
19 | return Column(
20 | children: const [
21 | SettingsOssTitle(),
22 | Expanded(child: SettingsOssBody()),
23 | ],
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Leafy Dev",
9 | "request": "launch",
10 | "type": "dart",
11 | "program": "lib/main_dev.dart",
12 | "args": [
13 | "--flavor",
14 | "dev"
15 | ],
16 | },
17 | {
18 | "name": "Leafy Prod",
19 | "request": "launch",
20 | "type": "dart",
21 | "program": "lib/main_prod.dart",
22 | "args": [
23 | "--flavor",
24 | "prod"
25 | ],
26 | }
27 | ]
28 | }
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/note/model/note_converter.dart:
--------------------------------------------------------------------------------
1 | import '../../../leafy_notes_db.dart';
2 | import 'note_model.dart';
3 |
4 | NoteModel noteModelFromDb(Note note) {
5 | return NoteModel(
6 | id: note.id,
7 | title: note.title,
8 | lastEditedAt: note.lastEditedAt,
9 | createdAt: note.createdAt,
10 | firstLine: note.firstLine,
11 | data: note.data,
12 | folderId: note.folderId,
13 | isArchived: note.isArchived,
14 | isPinned: note.isPinned,
15 | );
16 | }
17 |
18 | Note noteModelToDb(NoteModel note) {
19 | return Note(
20 | id: note.id,
21 | title: note.title,
22 | lastEditedAt: note.lastEditedAt,
23 | createdAt: note.createdAt,
24 | firstLine: note.firstLine,
25 | data: note.data,
26 | folderId: note.folderId,
27 | isArchived: note.isArchived,
28 | isPinned: note.isPinned,
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/module/home_notes/notes/note/home_note_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/base/page/status_page_base.dart';
3 | import 'package:leafy_launcher/module/home_notes/notes/note/widget/body/home_note_body.dart';
4 | import 'package:leafy_launcher/module/home_notes/notes/note/widget/title/home_note_title.dart';
5 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
6 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
7 |
8 | import 'home_note_controller.dart';
9 |
10 | class HomeNotePage extends StatusPageBase {
11 | const HomeNotePage();
12 |
13 | @override
14 | Widget ready(BuildContext context, LeafyTheme theme) {
15 | return Column(
16 | children: const [
17 | HomeNoteTitle(),
18 | HomeNoteBody(),
19 | ],
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/themed_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | import '../resources/theme/leafy_theme.dart';
5 |
6 | abstract class ThemedWidget extends StatelessWidget {
7 | const ThemedWidget({Key? key}) : super(key: key);
8 |
9 | @override
10 | @nonVirtual
11 | Widget build(BuildContext context) {
12 | final theme = context.dependOnInheritedWidgetOfExactType();
13 |
14 | assert(theme != null);
15 |
16 | if (theme == null) {
17 | return const ColoredBox(
18 | color: Colors.red,
19 | child: Padding(
20 | padding: EdgeInsets.all(8.0),
21 | child: Text('THEME NOT FOUND!'),
22 | ),
23 | );
24 | }
25 |
26 | return body(context, theme);
27 | }
28 |
29 | Widget body(BuildContext context, LeafyTheme theme);
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/home_settings_about_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../../../base/page/status_page_base.dart';
4 | import '../../../resources/theme/home_theme.dart';
5 | import '../../../resources/theme/leafy_theme.dart';
6 | import 'body/settings_about_body.dart';
7 | import 'home_settings_about_controller.dart';
8 | import 'title/home_settings_about_title.dart';
9 |
10 | class HomeSettingsAboutPage
11 | extends StatusPageBase {
12 | const HomeSettingsAboutPage();
13 |
14 | @override
15 | bool get resizeToAvoidBottomInset => false;
16 |
17 | @override
18 | Widget ready(BuildContext context, LeafyTheme theme) {
19 | return Column(
20 | children: const [
21 | SettingsAboutTitle(),
22 | Expanded(child: SettingsAboutBody()),
23 | ],
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/note/table/note_table.dart:
--------------------------------------------------------------------------------
1 | import 'package:moor_flutter/moor_flutter.dart';
2 |
3 | @DataClassName('Note')
4 | class Notes extends Table {
5 | TextColumn get id => text()();
6 | TextColumn get title => text().nullable().withDefault(const Constant(''))();
7 | TextColumn get firstLine =>
8 | text().nullable().withDefault(const Constant(''))();
9 | TextColumn get data => text().nullable().withDefault(const Constant(''))();
10 | DateTimeColumn get createdAt => dateTime()();
11 | DateTimeColumn get lastEditedAt => dateTime()();
12 | TextColumn get folderId =>
13 | text().customConstraint('REFERENCES folders(id)')();
14 | BoolColumn get isArchived => boolean().withDefault(const Constant(false))();
15 | BoolColumn get isPinned => boolean().withDefault(const Constant(false))();
16 |
17 | @override
18 | Set? get primaryKey => {id};
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/module/home/widget/corner_button/_other_apps_list.dart:
--------------------------------------------------------------------------------
1 | part of 'corner_button.dart';
2 |
3 | class _OtherAppsList extends StatelessWidget {
4 | const _OtherAppsList({
5 | Key? key,
6 | required this.types,
7 | required this.onPressed,
8 | }) : super(key: key);
9 |
10 | final Function(CornerButtonType type) onPressed;
11 | final Iterable types;
12 |
13 | List _getOtherTypesChildren() {
14 | return types
15 | .map(
16 | (item) => _ConfiguredIconButton(
17 | type: item,
18 | onPressed: () {
19 | onPressed(item);
20 | },
21 | ),
22 | )
23 | .toList();
24 | }
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Column(
29 | mainAxisSize: MainAxisSize.min,
30 | children: _getOtherTypesChildren(),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/lib/utils/enum/corner_button_type.dart:
--------------------------------------------------------------------------------
1 | enum CornerButtonType {
2 | phone,
3 | messages,
4 | camera,
5 | }
6 |
7 | const _phone = 'phone';
8 | const _messages = 'messages';
9 | const _camera = 'camera';
10 |
11 | String stringifyCornerButtonType(CornerButtonType type) {
12 | switch (type) {
13 | case CornerButtonType.phone:
14 | return _phone;
15 | case CornerButtonType.messages:
16 | return _messages;
17 | case CornerButtonType.camera:
18 | return _camera;
19 | default:
20 | throw Exception('Unknown type');
21 | }
22 | }
23 |
24 | CornerButtonType cornerButtonTypeFromString(String str) {
25 | switch (str) {
26 | case _phone:
27 | return CornerButtonType.phone;
28 | case _messages:
29 | return CornerButtonType.messages;
30 | case _camera:
31 | return CornerButtonType.camera;
32 | default:
33 | throw Exception('Unknown!');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/common/vibration.dart:
--------------------------------------------------------------------------------
1 | part of '../settings_body.dart';
2 |
3 | class _Vibration
4 | extends ThemedGetWidget {
5 | const _Vibration({Key? key}) : super(key: key);
6 |
7 | @override
8 | Widget body(BuildContext context, LeafyTheme theme) {
9 | return LeafySectionTextItem(
10 | title: L10nProvider.getText(L10n.settingsVibration),
11 | onTap: controller.toggleVibrationPreferences,
12 | value: GetBuilder(
13 | id: UserApplicationsController.kVibrationPreferencesBuilderKey,
14 | init: controller,
15 | builder: (_) {
16 | return LeafySectionTextValue(
17 | value: localizeVibrationPreferences(
18 | controller.vibrationPreferences,
19 | ),
20 | );
21 | },
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/assets/icons/telegram.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 |
4 | import 'applications/launcher/leafy_launcher.dart';
5 | import 'applications/notes/leafy_notes.dart';
6 | import 'utils/app_flavour/app_flavour.dart';
7 |
8 | const _appChannel = MethodChannel('com.nivisi.leafy_launcher/app');
9 |
10 | void main() => mainCommon(AppFlavour.dev);
11 |
12 | Future mainCommon(AppFlavour flavour) async {
13 | WidgetsFlutterBinding.ensureInitialized();
14 |
15 | // For a reason we cannot create another entry point for notes,
16 | // so we need to distinguish the app by calling a method channel.
17 |
18 | final app = await _appChannel.invokeMethod('app');
19 |
20 | switch (app) {
21 | case 'launcher':
22 | return LeafyLauncher.run(flavour);
23 | case 'leafyNotes':
24 | return LeafyNotes.run(flavour);
25 | }
26 |
27 | throw Exception('Tried to launch an unknown app!');
28 | }
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | *.lock
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Web related
36 | lib/generated_plugin_registrant.dart
37 |
38 | # Symbolication related
39 | app.*.symbols
40 |
41 | # Obfuscation related
42 | app.*.map.json
43 |
44 | # Android Studio will place build artifacts here
45 | /android/app/debug
46 | /android/app/profile
47 | /android/app/release
48 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss_license/home_settings_oss_license_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
3 |
4 | import '../../../base/page/status_page_base.dart';
5 | import '../../../resources/theme/leafy_theme.dart';
6 | import 'body/settings_oss_license_body.dart';
7 | import 'home_settings_oss_license_controller.dart';
8 | import 'title/home_settings_oss_license_title.dart';
9 |
10 | class HomeSettingsOssLicensePage
11 | extends StatusPageBase {
12 | const HomeSettingsOssLicensePage();
13 |
14 | @override
15 | bool get resizeToAvoidBottomInset => false;
16 |
17 | @override
18 | Widget ready(BuildContext context, LeafyTheme theme) {
19 | return Column(
20 | children: const [
21 | SettingsOssLicenseTitle(),
22 | Expanded(child: SettingsOssLicenseBody()),
23 | ],
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/android/app/src/main/kotlin/com/nivisi/leafy_launcher/broadcast_receivers/AppChangeReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.nivisi.leafy_launcher.broadcast_receivers
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import com.nivisi.leafy_launcher.MainActivity
7 |
8 | class AppChangeReceiver : BroadcastReceiver() {
9 |
10 | override fun onReceive(context: Context?, intent: Intent?) {
11 | val packageName = intent?.data?.encodedSchemeSpecificPart ?: return
12 |
13 | handle(intent.action, packageName, false)
14 | }
15 |
16 | companion object {
17 | fun handle(
18 | action: String?,
19 | packageName: String,
20 | replacing: Boolean
21 | ) {
22 | val isRemoved = action == Intent.ACTION_PACKAGE_REMOVED
23 |
24 | MainActivity.self?.dispatchAppChangedEvent(packageName, isRemoved)
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widgets/home_settings_widgets_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/module/home_settings/widgets/title/home_settings_widgets_title.dart';
3 |
4 | import '../../../base/page/status_page_base.dart';
5 | import '../../../resources/theme/home_theme.dart';
6 | import '../../../resources/theme/leafy_theme.dart';
7 | import 'body/settings_widgets_body.dart';
8 | import 'home_settings_widgets_controller.dart';
9 |
10 | class HomeSettingsWidgetsPage
11 | extends StatusPageBase {
12 | const HomeSettingsWidgetsPage();
13 |
14 | @override
15 | bool get resizeToAvoidBottomInset => false;
16 |
17 | @override
18 | Widget ready(BuildContext context, LeafyTheme theme) {
19 | return Column(
20 | children: const [
21 | SettingsWidgetsTitle(),
22 | Expanded(child: SettingsWidgetsBody()),
23 | ],
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/base/controller/controller_base.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../../utils/log/logable_mixin.dart';
5 |
6 | abstract class ControllerBase extends GetxController with LogableMixin {
7 | @protected
8 | Future resolveDependencies() async {}
9 |
10 | @protected
11 | @nonVirtual
12 | Future init() async {
13 | logger
14 | ..i('Initializing ...')
15 | ..i('Resolving dependencies ...');
16 |
17 | await resolveDependencies();
18 |
19 | logger.i('Initialized!');
20 | }
21 |
22 | Future back() async {
23 | final canClose = await this.canClose();
24 |
25 | if (!canClose) {
26 | return false;
27 | }
28 |
29 | Get.back();
30 |
31 | return false;
32 | }
33 |
34 | @override
35 | void onInit() {
36 | super.onInit();
37 |
38 | init();
39 | }
40 |
41 | Future canClose() async {
42 | return true;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib/utils/preferences/shared_preferences.dart:
--------------------------------------------------------------------------------
1 | import 'package:shared_preferences/shared_preferences.dart';
2 |
3 | const kThemeStyleKey = 'themeStyle';
4 | const kLocaleKey = 'locale';
5 | const kLocaleAsInSystem = 'localeAsSystem';
6 | const kLeftCornerButtonType = 'leftCornerButtonType';
7 | const kRightCornerButtonType = 'rightCornerButtonType';
8 | const kVibrationPreferences = 'vibrationPreferences';
9 | const kIsFirstLaunch = 'isFirstLaunch';
10 | const kIsTimeProgressVisible = 'isTimeProgressVisible';
11 | const kTimeProgressType = 'kTimeProgressType';
12 | const kIsCalendarVisible = 'isCalendarVisible';
13 | const kIsClockVisible = 'isClockVisible';
14 | const kIsLeftCornerButtonVisible = 'kIsLeftCornerButtonVisible';
15 | const kIsRightCornerButtonVisible = 'kIsRightCornerButtonVisible';
16 |
17 | late final SharedPreferences sharedPreferences;
18 |
19 | Future initSharedPreferences() async {
20 | sharedPreferences = await SharedPreferences.getInstance();
21 | }
22 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 | .vscode/*
34 | !.vscode/launch.json
35 |
36 | # Web related
37 | lib/generated_plugin_registrant.dart
38 |
39 | # Symbolication related
40 | app.*.symbols
41 |
42 | # Obfuscation related
43 | app.*.map.json
44 |
45 | # Android Studio will place build artifacts here
46 | /android/app/debug
47 | /android/app/profile
48 | /android/app/release
49 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/home_settings_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/app_constants.dart';
3 |
4 | import '../../base/page/status_page_base.dart';
5 | import '../../resources/theme/home_theme.dart';
6 | import '../../resources/theme/leafy_theme.dart';
7 | import 'home_settings_controller.dart';
8 | import 'widget/settings_body/settings_body.dart';
9 | import 'widget/settings_title/settings_title.dart';
10 |
11 | class HomeSettingsPage
12 | extends StatusPageBase {
13 | const HomeSettingsPage();
14 |
15 | static const horizontalPadding = kDefaultPadding * 2.0;
16 |
17 | @override
18 | bool get resizeToAvoidBottomInset => false;
19 |
20 | @override
21 | Widget ready(BuildContext context, LeafyTheme theme) {
22 | return Column(
23 | children: const [
24 | SettingsTitle(),
25 | Expanded(child: SettingsBody()),
26 | ],
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: leafy_launcher
2 | description: A new Flutter project.
3 |
4 | publish_to: 'none'
5 |
6 | version: 1.2.4
7 |
8 | environment:
9 | sdk: ">=2.15.0 <3.0.0"
10 |
11 | dependencies:
12 | assorted_layout_widgets: ^5.2.1
13 | ensure_initialized: ^0.1.0
14 | equatable: ^2.0.3
15 | flutter:
16 | sdk: flutter
17 | flutter_localizations:
18 | sdk: flutter
19 | flutter_oss_licenses: ^1.1.1
20 | flutter_svg: ^1.0.3
21 | fluttertoast: ^8.0.8
22 | get: ^4.5.1
23 | intl: ^0.17.0
24 | lint: ^1.8.1
25 | logger: ^1.0.0
26 | moor_flutter: ^4.0.0
27 | package_info_plus: ^1.3.0
28 | path_provider: ^2.0.2
29 | share: ^2.0.4
30 | shared_preferences: ^2.0.6
31 | synchronized: ^3.0.0
32 | table_calendar: ^3.0.2
33 | url_launcher: ^6.0.18
34 | uuid: ^3.0.5
35 |
36 | dev_dependencies:
37 | build_runner: ^2.1.5
38 | moor_generator: ^4.6.0+1
39 |
40 | flutter:
41 | uses-material-design: true
42 |
43 | assets:
44 | - assets/icons/
45 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/widget/theme.dart:
--------------------------------------------------------------------------------
1 | // part of '../settings_body.dart';
2 |
3 | // class _Theme extends ThemedGetWidget {
4 | // const _Theme({Key? key}) : super(key: key);
5 |
6 | // @override
7 | // Widget body(BuildContext context, LeafyTheme theme) {
8 | // return Column(
9 | // crossAxisAlignment: CrossAxisAlignment.start,
10 | // children: [
11 | // Text(
12 | // L10nProvider.getText(L10n.settingsTheme),
13 | // style: theme.bodyText3.copyWith(color: theme.textInfoColor),
14 | // ),
15 | // const LeafySpacer(),
16 | // TouchableTextButton(
17 | // text: theme.style.localize(),
18 | // style: theme.bodyText2,
19 | // color: theme.foregroundColor,
20 | // pressedColor: theme.foregroundPressedColor,
21 | // onTap: controller.changeTheme,
22 | // ),
23 | // ],
24 | // );
25 | // }
26 | // }
27 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/about/title/home_settings_about_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/localization/l10n.dart';
3 | import 'package:leafy_launcher/resources/localization/l10n_provider.dart';
4 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
5 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
6 | import 'package:leafy_launcher/shared_widget/page/page_header.dart';
7 | import 'package:leafy_launcher/shared_widget/themed_get_widget.dart';
8 |
9 | import '../home_settings_about_controller.dart';
10 |
11 | class SettingsAboutTitle
12 | extends ThemedGetWidget {
13 | const SettingsAboutTitle({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget body(BuildContext context, LeafyTheme theme) {
17 | return PageHeader(
18 | title: L10nProvider.getText(L10n.settingsAboutTitle),
19 | onTapped: controller.onTitleTapped,
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/module/app_picker/app_picker_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../../utils/enum/user_selected_app_type.dart';
4 | import 'app_picker_controller.dart';
5 | import 'app_picker_controller_base.dart';
6 |
7 | class AppPickerBinding implements Bindings {
8 | @override
9 | void dependencies() {
10 | final typeStr = Get.parameters['type'];
11 |
12 | UserSelectedAppType? type;
13 |
14 | if (typeStr != null) {
15 | type = userSelectedAppTypeFromString(typeStr);
16 | }
17 |
18 | final selectOnFirstMatchStr =
19 | Get.parameters[AppPickerControllerBase.selectOnFirstMatchParameter];
20 |
21 | var selectOnFirstMatch = false;
22 |
23 | if (selectOnFirstMatchStr != null) {
24 | selectOnFirstMatch = selectOnFirstMatchStr.toLowerCase() == 'true';
25 | }
26 |
27 | Get.put(
28 | AppPickerController(
29 | type: type,
30 | selectOnFirstMatch: selectOnFirstMatch,
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_title/settings_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/module/home_settings/home_settings_controller.dart';
3 | import 'package:leafy_launcher/resources/localization/l10n.dart';
4 | import 'package:leafy_launcher/resources/localization/l10n_provider.dart';
5 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
6 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
7 | import 'package:leafy_launcher/shared_widget/page/page_header.dart';
8 | import 'package:leafy_launcher/shared_widget/themed_get_widget.dart';
9 |
10 | class SettingsTitle extends ThemedGetWidget {
11 | const SettingsTitle({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget body(BuildContext context, LeafyTheme theme) {
15 | return PageHeader(
16 | title: L10nProvider.getText(L10n.settingsTitle),
17 | onTapped: controller.onTitleTapped,
18 | largerTitle: true,
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/module/startup/startup_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../../applications/launcher/app_routes.dart';
4 | import '../../base/controller/status_controller_base.dart';
5 | import '../../services/applications/installed_applications_service.dart';
6 | import '../../services/applications/user_applications_controller.dart';
7 |
8 | class StartupController extends StatusControllerBase {
9 | late final InstalledApplicationsService _installedApplicationsService;
10 | late final UserApplicationsController _userApplicationsController;
11 |
12 | @override
13 | Future resolveDependencies() async {
14 | _installedApplicationsService = Get.find();
15 | _userApplicationsController = Get.find();
16 | }
17 |
18 | @override
19 | Future load() async {
20 | await _installedApplicationsService.ensureInitialized;
21 | await _userApplicationsController.ensureInitialized;
22 |
23 | Get.offAndToNamed(AppRoutes.home);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss/title/home_settings_oss_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/module/home_settings/oss/home_settings_oss_controller.dart';
3 | import 'package:leafy_launcher/resources/localization/l10n.dart';
4 | import 'package:leafy_launcher/resources/localization/l10n_provider.dart';
5 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
6 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
7 | import 'package:leafy_launcher/shared_widget/page/page_header.dart';
8 | import 'package:leafy_launcher/shared_widget/themed_get_widget.dart';
9 |
10 | class SettingsOssTitle
11 | extends ThemedGetWidget {
12 | const SettingsOssTitle({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget body(BuildContext context, LeafyTheme theme) {
16 | return PageHeader(
17 | title: L10nProvider.getText(L10n.settingsAboutOssTitle),
18 | onTapped: controller.onTitleTapped,
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widgets/title/home_settings_widgets_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/module/home_settings/widgets/home_settings_widgets_controller.dart';
3 | import 'package:leafy_launcher/resources/localization/l10n.dart';
4 | import 'package:leafy_launcher/resources/localization/l10n_provider.dart';
5 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
6 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
7 | import 'package:leafy_launcher/shared_widget/page/page_header.dart';
8 | import 'package:leafy_launcher/shared_widget/themed_get_widget.dart';
9 |
10 | class SettingsWidgetsTitle
11 | extends ThemedGetWidget {
12 | const SettingsWidgetsTitle({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget body(BuildContext context, LeafyTheme theme) {
16 | return PageHeader(
17 | title: L10nProvider.getText(L10n.settingsWidgetsTitle),
18 | onTapped: controller.onTitleTapped,
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/take_tutorial/take_tutorial.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:leafy_launcher/shared_widget/section/src/items/values/leafy_section_chevron_value.dart';
4 |
5 | import '../../../../../resources/localization/l10n.dart';
6 | import '../../../../../resources/localization/l10n_provider.dart';
7 | import '../../../../../resources/theme/home_theme.dart';
8 | import '../../../../../services/applications/user_applications_controller.dart';
9 | import '../../../../../shared_widget/section/src/items/leafy_section_text_item.dart';
10 |
11 | class TakeTutorial extends GetWidget {
12 | const TakeTutorial({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return LeafySectionTextItem(
17 | title: L10nProvider.getText(L10n.settingsDoTutorial),
18 | onTap: controller.openTutorial,
19 | value: const LeafySectionChevronValue(),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/home_widgets/home_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:leafy_launcher/shared_widget/section/src/items/values/leafy_section_chevron_value.dart';
4 |
5 | import '../../../../../resources/localization/l10n.dart';
6 | import '../../../../../resources/localization/l10n_provider.dart';
7 | import '../../../../../resources/theme/home_theme.dart';
8 | import '../../../../../services/applications/user_applications_controller.dart';
9 | import '../../../../../shared_widget/section/src/items/leafy_section_text_item.dart';
10 |
11 | class HomeWidgets extends GetWidget {
12 | const HomeWidgets({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return LeafySectionTextItem(
17 | title: L10nProvider.getText(L10n.settingsHomeWidgetsConfigure),
18 | onTap: controller.openWidgets,
19 | value: const LeafySectionChevronValue(),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/themed_get_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:get/get.dart';
4 | import '../resources/theme/leafy_theme.dart';
5 |
6 | abstract class ThemedGetWidget extends GetView {
8 | const ThemedGetWidget({Key? key}) : super(key: key);
9 |
10 | @override
11 | TController get controller => GetInstance().find(tag: tag);
12 |
13 | @override
14 | @nonVirtual
15 | Widget build(BuildContext context) {
16 | final theme = context.dependOnInheritedWidgetOfExactType();
17 |
18 | assert(theme != null);
19 |
20 | if (theme == null) {
21 | return const ColoredBox(
22 | color: Colors.red,
23 | child: Padding(
24 | padding: EdgeInsets.all(8.0),
25 | child: Text('THEME NOT FOUND!'),
26 | ),
27 | );
28 | }
29 |
30 | return body(context, theme);
31 | }
32 |
33 | Widget body(BuildContext context, LeafyTheme theme);
34 | }
35 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/src/lib/module/home_notes/notes/folders/widget/title/home_note_folders_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/localization/l10n.dart';
3 | import 'package:leafy_launcher/resources/localization/l10n_provider.dart';
4 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
5 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
6 | import 'package:leafy_launcher/shared_widget/page/page_header.dart';
7 | import 'package:leafy_launcher/shared_widget/themed_get_widget.dart';
8 |
9 | import '../../home_note_folders_controller.dart';
10 |
11 | class HomeNoteFoldersTitle
12 | extends ThemedGetWidget {
13 | const HomeNoteFoldersTitle({
14 | Key? key,
15 | }) : super(key: key);
16 |
17 | @override
18 | Widget body(BuildContext context, LeafyTheme theme) {
19 | return PageHeader(
20 | title: L10nProvider.getText(L10n.leafyNotesFoldersTitle),
21 | hasBackButton: false,
22 | onTapped: controller.onTitleTapped,
23 | largerTitle: true,
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widget/settings_body/select_default_launcher/select_default_launcher.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:leafy_launcher/shared_widget/section/src/items/values/leafy_section_chevron_value.dart';
4 |
5 | import '../../../../../resources/localization/l10n.dart';
6 | import '../../../../../resources/localization/l10n_provider.dart';
7 | import '../../../../../resources/theme/home_theme.dart';
8 | import '../../../../../services/applications/user_applications_controller.dart';
9 | import '../../../../../shared_widget/section/src/items/leafy_section_text_item.dart';
10 |
11 | class SelectDefaultLauncher extends GetWidget {
12 | const SelectDefaultLauncher({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return LeafySectionTextItem(
17 | title: L10nProvider.getText(L10n.settingsDefaultLauncherChange),
18 | onTap: controller.openLauncherPreferences,
19 | value: const LeafySectionChevronValue(),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/widgets/widget/leafy_section_enabled_state_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/localization/l10n.dart';
3 | import 'package:leafy_launcher/resources/localization/l10n_provider.dart';
4 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
5 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
6 | import 'package:leafy_launcher/shared_widget/section/src/items/values/leafy_section_text_value.dart';
7 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
8 |
9 | class LeafySectionEnabledStateItem extends ThemedWidget {
10 | const LeafySectionEnabledStateItem({
11 | Key? key,
12 | required this.isEnabled,
13 | }) : super(key: key);
14 |
15 | final bool isEnabled;
16 |
17 | @override
18 | Widget body(BuildContext context, LeafyTheme theme) {
19 | final textKey =
20 | isEnabled ? L10n.settingsSectionEnabled : L10n.settingsSectionDisabled;
21 |
22 | return LeafySectionTextValue(
23 | value: L10nProvider.getText(textKey),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/services/device_locale/device_locale_changed_listener.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 |
6 | const _deviceLocaleChangedChannel = EventChannel(
7 | 'com.nivisi.leafy_launcher/deviceLocaleChangedChannel',
8 | );
9 |
10 | class DeviceLocaleChangedListener {
11 | DeviceLocaleChangedListener() {
12 | init();
13 | }
14 |
15 | final _controller = StreamController.broadcast();
16 | Stream get onDeviceLocaleChanged => _controller.stream;
17 |
18 | late StreamSubscription _subscription;
19 |
20 | void init() {
21 | _subscription = _deviceLocaleChangedChannel
22 | .receiveBroadcastStream()
23 | .listen(_onLocaleChanged);
24 | }
25 |
26 | void _onLocaleChanged(event) {
27 | if (event is! String) {
28 | throw Exception('event must be a string');
29 | }
30 |
31 | final split = event.split('-');
32 |
33 | final locale = Locale(split[0], split[1]);
34 |
35 | _controller.add(locale);
36 | }
37 |
38 | void dispose() {
39 | _subscription.cancel();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/lib/services/oss_licenses/oss_licenses_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:leafy_launcher/oss_licenses.dart';
2 | import 'package:leafy_launcher/services/oss_licenses/oss_license.dart';
3 | import 'package:leafy_launcher/utils/extensions/iterable_extensions.dart';
4 |
5 | class OssLicensesService {
6 | final List _licenses = [];
7 | Iterable get licenses => _licenses;
8 |
9 | OssLicensesService init() {
10 | for (final license in ossLicenses.entries) {
11 | final name = license.key;
12 | final data = license.value;
13 |
14 | if (data is! Map) {
15 | continue;
16 | }
17 |
18 | final ossLicense = OssLicense(
19 | name: name,
20 | version: data['version'] as String,
21 | description: data['description'] as String?,
22 | license: data['license'] as String,
23 | homepage: data['homepage'] as String?,
24 | );
25 |
26 | _licenses.add(ossLicense);
27 | }
28 |
29 | return this;
30 | }
31 |
32 | OssLicense? findByName(String name) {
33 | return _licenses.firstWhereOrNull((e) => e.name == name);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/leafy_spacer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../resources/app_constants.dart';
4 |
5 | enum LeafySpacerType {
6 | horizontal,
7 | vertical,
8 | }
9 |
10 | class LeafySpacer extends StatelessWidget {
11 | const LeafySpacer({
12 | Key? key,
13 | this.multipler = 1.0,
14 | this.type = LeafySpacerType.vertical,
15 | }) : super(key: key);
16 |
17 | const LeafySpacer.section({Key? key}) : this(key: key, multipler: 5.0);
18 |
19 | const LeafySpacer.horizontal({Key? key, double multipler = 1.0})
20 | : this(
21 | key: key,
22 | multipler: multipler,
23 | type: LeafySpacerType.horizontal,
24 | );
25 |
26 | final double multipler;
27 | final LeafySpacerType type;
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | switch (type) {
32 | case LeafySpacerType.vertical:
33 | return SizedBox(height: kDefaultPadding * multipler);
34 | case LeafySpacerType.horizontal:
35 | return SizedBox(width: kDefaultPadding * multipler);
36 | default:
37 | throw 'Unknown type';
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/module/home/widget/google_search/google_search_input.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../../../../resources/theme/home_theme.dart';
4 | import '../../../../resources/theme/leafy_theme.dart';
5 | import '../../../../shared_widget/themed_widget.dart';
6 |
7 | class GoogleSearchInput extends ThemedWidget {
8 | const GoogleSearchInput({
9 | Key? key,
10 | required this.controller,
11 | this.focusNode,
12 | this.onEditingComplete,
13 | }) : super(key: key);
14 |
15 | final TextEditingController controller;
16 | final FocusNode? focusNode;
17 | final void Function(String)? onEditingComplete;
18 |
19 | @override
20 | Widget body(BuildContext context, LeafyTheme theme) {
21 | return TextField(
22 | decoration: InputDecoration(
23 | filled: true,
24 | fillColor: theme.foregroundColor,
25 | prefixIcon: const Icon(Icons.search),
26 | ),
27 | controller: controller,
28 | focusNode: focusNode,
29 | onEditingComplete: onEditingComplete != null
30 | ? () {
31 | onEditingComplete!(controller.text);
32 | }
33 | : null,
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/lib/services/app_environment/app_environment.dart:
--------------------------------------------------------------------------------
1 | import 'package:leafy_launcher/utils/app_flavour/app_flavour.dart';
2 | import 'package:package_info_plus/package_info_plus.dart';
3 |
4 | class AppEnvironment {
5 | AppEnvironment(this._flavour);
6 |
7 | final AppFlavour _flavour;
8 |
9 | late final String _version;
10 | late final String _build;
11 | late final String _name;
12 | late final String _package;
13 |
14 | AppFlavour get flavour => _flavour;
15 | bool get isDev => _flavour == AppFlavour.dev;
16 | bool get isProd => _flavour == AppFlavour.prod;
17 |
18 | String get version => _version;
19 | String get build => _build;
20 | String get name => _name;
21 | String get package => _package;
22 |
23 | String get github => 'https://github.com/nivisi/LeafyLauncher';
24 | String get email => 'leafylauncher@gmail.com';
25 | String get telegramChat => 'https://t.me/+MJJJZbkBNpdhMzdi';
26 |
27 | Future init() async {
28 | final packageInfo = await PackageInfo.fromPlatform();
29 |
30 | _name = packageInfo.appName;
31 | _package = packageInfo.packageName;
32 | _version = packageInfo.version;
33 | _build = packageInfo.buildNumber;
34 |
35 | return this;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/list/dismissible_delete_background.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/module/home/utils/gesture_processer.dart';
3 | import 'package:leafy_launcher/resources/app_constants.dart';
4 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
5 |
6 | import '../themed_widget.dart';
7 |
8 | class DismissibleDeleteBackground
9 | extends ThemedWidget {
10 | const DismissibleDeleteBackground(this.direction);
11 |
12 | final Direction direction;
13 |
14 | @override
15 | Widget body(BuildContext context, LeafyTheme theme) {
16 | final alignment = direction == Direction.right
17 | ? Alignment.centerRight
18 | : Alignment.centerLeft;
19 |
20 | final padding = direction == Direction.right
21 | ? const EdgeInsets.only(right: kDefaultPadding)
22 | : const EdgeInsets.only(left: kDefaultPadding);
23 |
24 | return Container(
25 | padding: padding,
26 | color: theme.deleteColor,
27 | child: Align(
28 | alignment: alignment,
29 | child: Icon(
30 | Icons.delete_forever_rounded,
31 | color: theme.foregroundColor,
32 | ),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/lib/utils/enum/leafy_theme_style.dart:
--------------------------------------------------------------------------------
1 | import '../../resources/localization/l10n.dart';
2 | import '../../resources/localization/l10n_provider.dart';
3 |
4 | enum LeafyThemeStyle {
5 | light,
6 | dark,
7 | }
8 |
9 | extension LeafyThemeStyleExtensions on LeafyThemeStyle {
10 | String localize() {
11 | switch (this) {
12 | case LeafyThemeStyle.light:
13 | return L10nProvider.getText(L10n.themeStyleLight);
14 | case LeafyThemeStyle.dark:
15 | return L10nProvider.getText(L10n.themeStyleDark);
16 | default:
17 | throw Exception('Unknown type');
18 | }
19 | }
20 | }
21 |
22 | const String _light = 'Light';
23 | const String _dark = 'Dark';
24 |
25 | String stringifyLeafyThemeStyle(LeafyThemeStyle style) {
26 | switch (style) {
27 | case LeafyThemeStyle.light:
28 | return _light;
29 | case LeafyThemeStyle.dark:
30 | return _dark;
31 |
32 | default:
33 | throw Exception('Unknown type');
34 | }
35 | }
36 |
37 | LeafyThemeStyle leafyThemeStyleFromString(String str) {
38 | switch (str) {
39 | case _light:
40 | return LeafyThemeStyle.light;
41 | case _dark:
42 | return LeafyThemeStyle.dark;
43 | default:
44 | throw Exception('Unknown!');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/lib/module/app_picker/widget/app_picker_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../../../resources/theme/home_theme.dart';
4 | import '../../../resources/theme/leafy_theme.dart';
5 | import '../../../services/applications/application.dart';
6 | import '../../../shared_widget/themed_widget.dart';
7 | import '../../../shared_widget/touchable_text_button.dart';
8 |
9 | class AppPickerButton extends ThemedWidget {
10 | const AppPickerButton({
11 | Key? key,
12 | required this.application,
13 | required this.onTapped,
14 | this.onLongPress,
15 | }) : super(key: key);
16 |
17 | final Application application;
18 | final void Function(Application app) onTapped;
19 | final void Function(Application app)? onLongPress;
20 |
21 | @override
22 | Widget body(BuildContext context, LeafyTheme theme) {
23 | return TouchableTextButton(
24 | text: application.name,
25 | color: theme.foregroundColor,
26 | pressedColor: theme.foregroundPressedColor,
27 | style: theme.bodyText1,
28 | onTap: () {
29 | onTapped(application);
30 | },
31 | onLongPress: onLongPress == null
32 | ? null
33 | : () {
34 | onLongPress!(application);
35 | },
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/assets/icons/github.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/lib/resources/app_constants.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const kButtonPressForwardAnimationDuration = Duration(milliseconds: 15);
4 | const kButtonPressReverseAnimationDuration = Duration(milliseconds: 100);
5 | const kDefaultAnimationDuration = Duration(milliseconds: 250);
6 | const kDefaultRouteTransitionDuration = Duration(milliseconds: 100);
7 | const kAppRefetchDuration = Duration(minutes: 10);
8 |
9 | const kDefaultPadding = 10.0;
10 |
11 | const kHomeHorizontalPadding = kDefaultPadding * 2.5;
12 | const kHomeVerticalPadding = kDefaultPadding * 4.0;
13 | const kStatusBarPadding = 20.0;
14 | const kHomeAppsSpacingMultipler = 2.0;
15 | const kHomeHorizontalSwipeIconSize = 55.0;
16 | const kHomeCornerButtonEdgeInsets = EdgeInsets.only(
17 | left: kDefaultPadding * 1.3,
18 | right: kDefaultPadding * 1.3,
19 | bottom: kDefaultPadding,
20 | );
21 | const kHomeSearchOffsetMultipler = 50.0;
22 |
23 | const kBarrierColor = Color(0x66000000);
24 |
25 | const kUserAppListTopPadding = EdgeInsets.only(top: kDefaultPadding * 7.5);
26 |
27 | const kSettingsIcon = Icons.settings;
28 | const kCameraAppIcon = Icons.camera_alt;
29 | const kPhoneAppIcon = Icons.phone;
30 | const kMessagesAppIcon = Icons.message;
31 |
32 | const kDefaultAnimationCurve = Curves.fastOutSlowIn;
33 | const kDefaultBorderRadius = BorderRadius.all(Radius.circular(10.0));
34 |
--------------------------------------------------------------------------------
/src/lib/module/home_notes/notes/folders/home_note_folders_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/base/page/page_base.dart';
3 | import 'package:leafy_launcher/base/page/status_page_base.dart';
4 | import 'package:leafy_launcher/resources/app_constants.dart';
5 | import 'package:leafy_launcher/resources/theme/home_theme.dart';
6 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
7 |
8 | import 'home_note_folders_controller.dart';
9 | import 'widget/fab/home_note_folders_fab.dart';
10 | import 'widget/list/home_note_folders_list.dart';
11 | import 'widget/title/home_note_folders_title.dart';
12 |
13 | class HomeNoteFoldersPage
14 | extends StatusPageBase {
15 | const HomeNoteFoldersPage();
16 |
17 | static const horizontalPadding = kDefaultPadding;
18 |
19 | @override
20 | OnWillPopData get onWillPopData => OnWillPopData(controller.back);
21 |
22 | @override
23 | Widget ready(BuildContext context, LeafyTheme theme) {
24 | return Column(
25 | crossAxisAlignment: CrossAxisAlignment.stretch,
26 | children: const [
27 | HomeNoteFoldersTitle(),
28 | Expanded(child: HomeNoteFoldersList()),
29 | ],
30 | );
31 | }
32 |
33 | @override
34 | Widget fab(BuildContext context, LeafyTheme theme) {
35 | return const HomeNoteFoldersFab();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/android/app/src/main/kotlin/com/nivisi/leafy_launcher/installed_packages/LauncherAppsCallback.kt:
--------------------------------------------------------------------------------
1 | package com.nivisi.leafy_launcher.installed_packages
2 |
3 | import android.content.pm.LauncherApps
4 | import android.os.UserHandle
5 | import com.nivisi.leafy_launcher.broadcast_receivers.AppChangeReceiver
6 |
7 | class LauncherAppsCallback : LauncherApps.Callback() {
8 | override fun onPackageAdded(packageName: String, user: UserHandle) {
9 | AppChangeReceiver.handle(
10 | "android.intent.action.PACKAGE_ADDED",
11 | packageName,
12 | false
13 | )
14 | }
15 |
16 | override fun onPackageChanged(packageName: String, user: UserHandle) {
17 | // Not implemented
18 | }
19 |
20 | override fun onPackageRemoved(packageName: String, user: UserHandle) {
21 | AppChangeReceiver.handle(
22 | "android.intent.action.PACKAGE_REMOVED",
23 | packageName,
24 | false
25 | )
26 | }
27 |
28 |
29 | override fun onPackagesAvailable(
30 | packageNames: Array?,
31 | user: UserHandle?,
32 | replacing: Boolean
33 | ) {
34 | // Not implemented
35 | }
36 |
37 | override fun onPackagesUnavailable(
38 | packageNames: Array?,
39 | user: UserHandle?,
40 | replacing: Boolean
41 | ) {
42 | // Not implemented
43 | }
44 | }
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/items/leafy_section_text_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/theme/leafy_theme.dart';
3 | import 'package:leafy_launcher/shared_widget/themed_widget.dart';
4 |
5 | import 'leafy_section_custom_item.dart';
6 |
7 | class LeafySectionTextItem
8 | extends ThemedWidget {
9 | const LeafySectionTextItem({
10 | Key? key,
11 | required this.title,
12 | this.subtitle,
13 | this.leading,
14 | this.value,
15 | this.onTap,
16 | this.onLongPress,
17 | }) : super(key: key);
18 |
19 | final String title;
20 | final String? subtitle;
21 | final Widget? leading;
22 | final Widget? value;
23 | final VoidCallback? onTap;
24 | final VoidCallback? onLongPress;
25 |
26 | @override
27 | Widget body(BuildContext context, LeafyTheme theme) {
28 | return LeafySectionCustomItem(
29 | title: Text(
30 | title,
31 | style: theme.bodyText5,
32 | maxLines: 1,
33 | overflow: TextOverflow.ellipsis,
34 | ),
35 | subtitle: subtitle != null
36 | ? Text(
37 | subtitle!,
38 | style: theme.bodyText4.copyWith(color: theme.textInfoColor),
39 | )
40 | : null,
41 | onTap: onTap,
42 | onLongPress: onLongPress,
43 | leading: leading,
44 | value: value,
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/lib/shared_widget/section/src/theme/leafy_section_theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leafy_launcher/resources/app_constants.dart';
3 |
4 | class LeafySectionTheme extends InheritedWidget {
5 | const LeafySectionTheme({
6 | Key? key,
7 | required Widget child,
8 | this.leadingAlwaysTakesSpace = false,
9 | required this.leadingWidth,
10 | this.itemHorizontalPadding = kDefaultPadding,
11 | this.itemVerticalPadding = kDefaultPadding * 1.5,
12 | this.backgroundColor = Colors.transparent,
13 | this.sectionBorderRadius = BorderRadius.zero,
14 | }) : super(
15 | key: key,
16 | child: child,
17 | );
18 |
19 | final bool leadingAlwaysTakesSpace;
20 | final double leadingWidth;
21 | final double itemHorizontalPadding;
22 | final double itemVerticalPadding;
23 | final Color backgroundColor;
24 | final BorderRadius sectionBorderRadius;
25 |
26 | @override
27 | bool updateShouldNotify(covariant LeafySectionTheme oldWidget) {
28 | return leadingAlwaysTakesSpace != oldWidget.leadingAlwaysTakesSpace;
29 | }
30 |
31 | LeafySectionTheme? of(BuildContext context) {
32 | return context.dependOnInheritedWidgetOfExactType();
33 | }
34 | }
35 |
36 | extension LeafySectionFinder on BuildContext {
37 | LeafySectionTheme? get leafySectionTheme =>
38 | dependOnInheritedWidgetOfExactType();
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/module/home_settings/oss/home_settings_oss_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:leafy_launcher/applications/launcher/app_routes.dart';
4 | import 'package:leafy_launcher/resources/app_constants.dart';
5 | import 'package:leafy_launcher/services/oss_licenses/oss_license.dart';
6 | import 'package:leafy_launcher/services/oss_licenses/oss_licenses_service.dart';
7 |
8 | import '../../../base/controller/status_controller_base.dart';
9 |
10 | class HomeSettingsOssController extends StatusControllerBase {
11 | late final OssLicensesService _ossLicensesService;
12 | late final ScrollController scrollController;
13 |
14 | Iterable get licenses => _ossLicensesService.licenses;
15 |
16 | @override
17 | Future resolveDependencies() {
18 | _ossLicensesService = Get.find();
19 |
20 | return super.resolveDependencies();
21 | }
22 |
23 | @override
24 | Future load() async {
25 | await super.load();
26 |
27 | scrollController = ScrollController();
28 | }
29 |
30 | void openLibrary(OssLicense license) {
31 | AppRoutes.toOssLicense(name: license.name);
32 | }
33 |
34 | void onTitleTapped() {
35 | if (scrollController.hasClients) {
36 | scrollController.animateTo(
37 | .0,
38 | duration: kDefaultAnimationDuration,
39 | curve: kDefaultAnimationCurve,
40 | );
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/lib/database/leafy_notes_db/src/models/folder/model/folder_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:equatable/equatable.dart';
2 |
3 | class FolderModel extends Equatable {
4 | const FolderModel({
5 | required this.id,
6 | required this.title,
7 | required this.lastEditedAt,
8 | required this.createdAt,
9 | required this.isDefault,
10 | required this.isArchived,
11 | required this.isPinned,
12 | });
13 |
14 | final String id;
15 | final String title;
16 | final DateTime lastEditedAt;
17 | final DateTime createdAt;
18 | final bool isDefault;
19 | final bool isArchived;
20 | final bool isPinned;
21 |
22 | FolderModel copyWith({
23 | String? id,
24 | String? title,
25 | DateTime? lastEditedAt,
26 | DateTime? createdAt,
27 | bool? isDefault,
28 | bool? isArchived,
29 | bool? isPinned,
30 | }) {
31 | return FolderModel(
32 | id: id ?? this.id,
33 | title: title ?? this.title,
34 | lastEditedAt: lastEditedAt ?? this.lastEditedAt,
35 | createdAt: createdAt ?? this.createdAt,
36 | isDefault: isDefault ?? this.isDefault,
37 | isArchived: isArchived ?? this.isArchived,
38 | isPinned: isDefault ?? this.isPinned,
39 | );
40 | }
41 |
42 | @override
43 | List