├── .github └── workflows │ └── main.yml ├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── icon.svg ├── misc.xml ├── modules.xml ├── runConfigurations.xml ├── runConfigurations │ ├── Code_Generation.xml │ ├── main_dart.xml │ └── main_dart__profiling_.xml └── vcs.xml ├── .metadata ├── LICENSE.txt ├── README.md ├── Windows-zip-release.bat ├── Windows-zip-release.py ├── analysis_options.yaml ├── assets ├── SMOL_Themes.json ├── common │ └── JpsAtHome.jar ├── fonts │ ├── Orbitron-Black.ttf │ ├── Orbitron-Bold.ttf │ ├── Orbitron-ExtraBold.ttf │ ├── Orbitron-Medium.ttf │ ├── Orbitron-Regular.ttf │ └── Orbitron-SemiBold.ttf ├── images │ ├── arrow_down.png │ ├── arrow_down2.png │ ├── button_up.png │ ├── chipper │ │ └── icon.png │ ├── construction.png │ ├── icon-account-box-outline.svg │ ├── icon-admin-shield-half.svg │ ├── icon-admin-shield.svg │ ├── icon-archive-create.svg │ ├── icon-archive.svg │ ├── icon-arrow-down.svg │ ├── icon-arrow-split-vertical.svg │ ├── icon-arrow-up.svg │ ├── icon-bookshelf.svg │ ├── icon-broom.svg │ ├── icon-bullhorn-variant.svg │ ├── icon-check.svg │ ├── icon-clone.svg │ ├── icon-collapse.svg │ ├── icon-console.svg │ ├── icon-copy.svg │ ├── icon-dead.svg │ ├── icon-death-star.svg │ ├── icon-debug.svg │ ├── icon-dice.svg │ ├── icon-direct-install.svg │ ├── icon-discord-white.svg │ ├── icon-donate.svg │ ├── icon-done.svg │ ├── icon-drag-horizontal.svg │ ├── icon-edit.svg │ ├── icon-exclamation.svg │ ├── icon-expand.svg │ ├── icon-experimental.svg │ ├── icon-file-debug.svg │ ├── icon-file-history.svg │ ├── icon-file-settings.svg │ ├── icon-folder-game.svg │ ├── icon-folder-mods.svg │ ├── icon-folder-multiple.svg │ ├── icon-folder-open.svg │ ├── icon-folder-saves.svg │ ├── icon-folder.svg │ ├── icon-github.svg │ ├── icon-group.svg │ ├── icon-help-circled.svg │ ├── icon-help.svg │ ├── icon-hide.svg │ ├── icon-ice-cream.svg │ ├── icon-image.svg │ ├── icon-incognito-circle.svg │ ├── icon-info.svg │ ├── icon-log.svg │ ├── icon-maximize.svg │ ├── icon-menu-down.svg │ ├── icon-more-horz.svg │ ├── icon-new-folder.svg │ ├── icon-new-update-search.svg │ ├── icon-new-update.svg │ ├── icon-nexus.svg │ ├── icon-not-upcoming.svg │ ├── icon-onslaught.svg │ ├── icon-open-folder.svg │ ├── icon-open-in-app.svg │ ├── icon-open-in-new.svg │ ├── icon-package-check.svg │ ├── icon-patreon.svg │ ├── icon-plus.svg │ ├── icon-podium-bronze.svg │ ├── icon-podium-gold.svg │ ├── icon-podium-silver.svg │ ├── icon-power.svg │ ├── icon-refresh.svg │ ├── icon-remove.svg │ ├── icon-repair.svg │ ├── icon-save.svg │ ├── icon-search.svg │ ├── icon-settings.svg │ ├── icon-show.svg │ ├── icon-shredder.svg │ ├── icon-skip.svg │ ├── icon-spider-web.svg │ ├── icon-stable.svg │ ├── icon-swap-upgrade.svg │ ├── icon-swap.svg │ ├── icon-tag.svg │ ├── icon-target.svg │ ├── icon-test-radioactive.svg │ ├── icon-text-box-edit.svg │ ├── icon-text.svg │ ├── icon-tips.svg │ ├── icon-toolbox.svg │ ├── icon-traffic-cone.svg │ ├── icon-trash.svg │ ├── icon-update-badge.svg │ ├── icon-utility-mod.svg │ ├── icon-view-carousel.svg │ ├── icon-vram-impact.svg │ ├── icon-warning.svg │ ├── icon-web.svg │ ├── icon-weight.svg │ ├── icon-yawn.svg │ ├── kotlin-icon.svg │ ├── telos_faction_crest.png │ └── telos_faction_crest.svg ├── linux │ ├── 7zip │ │ ├── arm64 │ │ │ ├── 7zzs │ │ │ ├── License.txt │ │ │ └── readme.txt │ │ └── x64 │ │ │ ├── 7zzs │ │ │ ├── License.txt │ │ │ └── readme.txt │ └── libarchive │ │ ├── bin │ │ ├── bsdcat │ │ ├── bsdcpio │ │ ├── bsdtar │ │ └── bsdunzip │ │ ├── include │ │ ├── archive.h │ │ └── archive_entry.h │ │ ├── lib │ │ ├── libarchive.a │ │ ├── libarchive.la │ │ ├── libarchive.so │ │ └── pkgconfig │ │ │ └── libarchive.pc │ │ └── share │ │ └── man │ │ ├── man1 │ │ ├── bsdcat.1 │ │ ├── bsdcpio.1 │ │ ├── bsdtar.1 │ │ └── bsdunzip.1 │ │ ├── man3 │ │ ├── archive_entry.3 │ │ ├── archive_entry_acl.3 │ │ ├── archive_entry_linkify.3 │ │ ├── archive_entry_misc.3 │ │ ├── archive_entry_paths.3 │ │ ├── archive_entry_perms.3 │ │ ├── archive_entry_stat.3 │ │ ├── archive_entry_time.3 │ │ ├── archive_read.3 │ │ ├── archive_read_add_passphrase.3 │ │ ├── archive_read_data.3 │ │ ├── archive_read_disk.3 │ │ ├── archive_read_extract.3 │ │ ├── archive_read_filter.3 │ │ ├── archive_read_format.3 │ │ ├── archive_read_free.3 │ │ ├── archive_read_header.3 │ │ ├── archive_read_new.3 │ │ ├── archive_read_open.3 │ │ ├── archive_read_set_options.3 │ │ ├── archive_util.3 │ │ ├── archive_write.3 │ │ ├── archive_write_blocksize.3 │ │ ├── archive_write_data.3 │ │ ├── archive_write_disk.3 │ │ ├── archive_write_filter.3 │ │ ├── archive_write_finish_entry.3 │ │ ├── archive_write_format.3 │ │ ├── archive_write_free.3 │ │ ├── archive_write_header.3 │ │ ├── archive_write_new.3 │ │ ├── archive_write_open.3 │ │ ├── archive_write_set_options.3 │ │ ├── archive_write_set_passphrase.3 │ │ ├── libarchive.3 │ │ ├── libarchive_changes.3 │ │ └── libarchive_internals.3 │ │ └── man5 │ │ ├── cpio.5 │ │ ├── libarchive-formats.5 │ │ ├── mtree.5 │ │ └── tar.5 ├── macos │ ├── 7zip │ │ ├── 7zz │ │ ├── License.txt │ │ └── readme.txt │ └── libarchive │ │ ├── bin │ │ ├── bsdcat │ │ ├── bsdcpio │ │ ├── bsdtar │ │ └── bsdunzip │ │ ├── include │ │ ├── archive.h │ │ └── archive_entry.h │ │ ├── lib │ │ ├── libarchive.13.dylib │ │ ├── libarchive.a │ │ ├── libarchive.dylib │ │ ├── libarchive.la │ │ └── pkgconfig │ │ │ └── libarchive.pc │ │ └── share │ │ └── man │ │ ├── man1 │ │ ├── bsdcat.1 │ │ ├── bsdcpio.1 │ │ ├── bsdtar.1 │ │ └── bsdunzip.1 │ │ ├── man3 │ │ ├── archive_entry.3 │ │ ├── archive_entry_acl.3 │ │ ├── archive_entry_linkify.3 │ │ ├── archive_entry_misc.3 │ │ ├── archive_entry_paths.3 │ │ ├── archive_entry_perms.3 │ │ ├── archive_entry_stat.3 │ │ ├── archive_entry_time.3 │ │ ├── archive_read.3 │ │ ├── archive_read_add_passphrase.3 │ │ ├── archive_read_data.3 │ │ ├── archive_read_disk.3 │ │ ├── archive_read_extract.3 │ │ ├── archive_read_filter.3 │ │ ├── archive_read_format.3 │ │ ├── archive_read_free.3 │ │ ├── archive_read_header.3 │ │ ├── archive_read_new.3 │ │ ├── archive_read_open.3 │ │ ├── archive_read_set_options.3 │ │ ├── archive_util.3 │ │ ├── archive_write.3 │ │ ├── archive_write_blocksize.3 │ │ ├── archive_write_data.3 │ │ ├── archive_write_disk.3 │ │ ├── archive_write_filter.3 │ │ ├── archive_write_finish_entry.3 │ │ ├── archive_write_format.3 │ │ ├── archive_write_free.3 │ │ ├── archive_write_header.3 │ │ ├── archive_write_new.3 │ │ ├── archive_write_open.3 │ │ ├── archive_write_set_options.3 │ │ ├── archive_write_set_passphrase.3 │ │ ├── libarchive.3 │ │ ├── libarchive_changes.3 │ │ └── libarchive_internals.3 │ │ └── man5 │ │ ├── cpio.5 │ │ ├── libarchive-formats.5 │ │ ├── mtree.5 │ │ └── tar.5 └── windows │ ├── 7zip │ ├── 7-zip.dll │ ├── 7z.dll │ ├── 7z.exe │ └── Codecs │ │ ├── LICENSE │ │ ├── README.md │ │ ├── brotli.dll │ │ ├── flzma2.dll │ │ ├── lizard.dll │ │ ├── lz4.dll │ │ ├── lz5.dll │ │ └── zstd.dll │ └── libarchive │ ├── bin │ ├── archive.dll │ ├── bz2.dll │ ├── iconv-2.dll │ ├── libcrypto-3-x64.dll │ ├── liblzma.dll │ ├── libxml2.dll │ ├── lz4.dll │ ├── zlib1.dll │ └── zstd.dll │ ├── include │ ├── archive.h │ └── archive_entry.h │ ├── lib │ ├── archive.lib │ ├── archive_static.lib │ └── pkgconfig │ │ └── libarchive.pc │ └── share │ └── man │ ├── man1 │ ├── bsdcat.1 │ ├── bsdcpio.1 │ └── bsdtar.1 │ ├── man3 │ ├── archive_entry.3 │ ├── archive_entry_acl.3 │ ├── archive_entry_linkify.3 │ ├── archive_entry_misc.3 │ ├── archive_entry_paths.3 │ ├── archive_entry_perms.3 │ ├── archive_entry_stat.3 │ ├── archive_entry_time.3 │ ├── archive_read.3 │ ├── archive_read_add_passphrase.3 │ ├── archive_read_data.3 │ ├── archive_read_disk.3 │ ├── archive_read_extract.3 │ ├── archive_read_filter.3 │ ├── archive_read_format.3 │ ├── archive_read_free.3 │ ├── archive_read_header.3 │ ├── archive_read_new.3 │ ├── archive_read_open.3 │ ├── archive_read_set_options.3 │ ├── archive_util.3 │ ├── archive_write.3 │ ├── archive_write_blocksize.3 │ ├── archive_write_data.3 │ ├── archive_write_disk.3 │ ├── archive_write_filter.3 │ ├── archive_write_finish_entry.3 │ ├── archive_write_format.3 │ ├── archive_write_free.3 │ ├── archive_write_header.3 │ ├── archive_write_new.3 │ ├── archive_write_open.3 │ ├── archive_write_set_options.3 │ ├── archive_write_set_passphrase.3 │ ├── libarchive.3 │ ├── libarchive_changes.3 │ └── libarchive_internals.3 │ └── man5 │ ├── cpio.5 │ ├── libarchive-formats.5 │ ├── mtree.5 │ └── tar.5 ├── build.yaml ├── build_bit7z_bindings.yaml ├── build_libarchive_bindings.yaml ├── changelog.md ├── devtools_options.yaml ├── lib ├── about │ └── about_page.dart ├── app_shell.dart ├── catalog │ ├── mod_browser_manager.dart │ ├── mod_browser_page.dart │ ├── models │ │ ├── scraped_mod.dart │ │ └── scraped_mod.mapper.dart │ └── scraped_mod_card.dart ├── changelogs │ ├── mod_changelogs_manager.dart │ └── mod_changelogs_manager.mapper.dart ├── chipper │ ├── chipper_home.dart │ ├── chipper_state.dart │ ├── copy.dart │ ├── logparser.dart │ ├── models │ │ ├── error_lines.dart │ │ ├── mod_entry.dart │ │ └── user_mods.dart │ ├── selection_transformer.dart │ ├── utils.dart │ └── views │ │ ├── about_view.dart │ │ ├── chipper_home.dart │ │ ├── chipper_log.dart │ │ ├── lights.dart │ │ ├── readout.dart │ │ └── wavy_painter.dart ├── compression │ ├── archive.dart │ ├── libarchive │ │ ├── libarchive.dart │ │ └── libarchive_bindings.dart │ └── seven_zip │ │ └── seven_zip.dart ├── dashboard │ ├── changelogs.dart │ ├── dashboard.dart │ ├── game_settings_manager.dart │ ├── game_settings_manager.mapper.dart │ ├── launch_with_settings.dart │ ├── mod_dependencies_widget.dart │ ├── mod_list_basic.dart │ ├── mod_list_basic_entry.dart │ ├── mod_summary_widget.dart │ ├── version_check_icon.dart │ └── version_check_text_readout.dart ├── jre_manager │ ├── game_performance_widget.dart │ ├── jre_entry.dart │ ├── jre_entry.mapper.dart │ ├── jre_manager_logic.dart │ └── ram_changer.dart ├── launcher │ └── launcher.dart ├── main.dart ├── mod_manager │ ├── audit_log.dart │ ├── audit_page.dart │ ├── copy_mod_list_button.dart │ ├── filter_mods_search_view.dart │ ├── homebrew_grid │ │ ├── wisp_grid.dart │ │ ├── wisp_grid_state.dart │ │ ├── wisp_grid_state.mapper.dart │ │ ├── wispgrid_group.dart │ │ ├── wispgrid_group_row.dart │ │ ├── wispgrid_header_row_view.dart │ │ └── wispgrid_row_view.dart │ ├── mod_context_menu.dart │ ├── mod_install_source.dart │ ├── mod_manager_extensions.dart │ ├── mod_manager_logic.dart │ ├── mod_summary_panel.dart │ ├── mod_version_selection_dropdown.dart │ ├── mods_grid_page.dart │ ├── version_checker.dart │ ├── version_checker.mapper.dart │ └── vram_checker_explanation.dart ├── mod_profiles │ ├── mod_profiles_manager.dart │ ├── mod_profiles_page.dart │ ├── models │ │ ├── mod_profile.dart │ │ └── mod_profile.mapper.dart │ └── save_reader.dart ├── models │ ├── download_progress.dart │ ├── download_progress.mapper.dart │ ├── enabled_mods.dart │ ├── enabled_mods.mapper.dart │ ├── launch_settings.dart │ ├── launch_settings.mapper.dart │ ├── mod.dart │ ├── mod.mapper.dart │ ├── mod_info.dart │ ├── mod_info.mapper.dart │ ├── mod_info_json.dart │ ├── mod_info_json.mapper.dart │ ├── mod_variant.dart │ ├── mod_variant.mapper.dart │ ├── version.dart │ ├── version.mapper.dart │ ├── version_checker_info.dart │ └── version_checker_info.mapper.dart ├── onboarding │ └── onboarding_page.dart ├── portraits │ ├── portraits_loader.dart │ └── portraits_viewer.dart ├── rules_autofresh │ ├── all_seeing_eye.dart │ └── rules_hotreload.dart ├── shipSystemsManager │ ├── ship_system.dart │ ├── ship_system.mapper.dart │ └── ship_systems_manager.dart ├── shipViewer │ ├── models │ │ ├── ship.dart │ │ ├── shipCsv.dart │ │ ├── shipEngineSlot.dart │ │ ├── shipEngineSlotChange.dart │ │ ├── shipEngineStyleSpec.dart │ │ ├── shipGpt.dart │ │ ├── shipGpt.mapper.dart │ │ ├── shipJson.dart │ │ ├── shipSkin.dart │ │ ├── shipWeaponSlotChange.dart │ │ ├── ship_weapon_slot.dart │ │ ├── ship_weapon_slot.mapper.dart │ │ ├── variant.dart │ │ └── variantWeapon.dart │ ├── shipManager.dart │ └── shipsPage.dart ├── themes │ ├── theme.dart │ ├── theme_manager.dart │ └── theme_manager.mapper.dart ├── thirdparty │ ├── dartx │ │ ├── arithmetic.dart │ │ ├── comparable.dart │ │ ├── comparator.dart │ │ ├── function.dart │ │ ├── int.dart │ │ ├── io │ │ │ ├── directory.dart │ │ │ ├── file.dart │ │ │ └── file_system_entity.dart │ │ ├── iterable.dart │ │ ├── iterable_num.dart │ │ ├── list.dart │ │ ├── map.dart │ │ ├── num.dart │ │ ├── range.dart │ │ ├── sorted_list.dart │ │ └── string.dart │ └── flutter_context_menu │ │ ├── components │ │ ├── generic_context_menu.dart │ │ ├── menu_divider.dart │ │ ├── menu_header.dart │ │ └── menu_item.dart │ │ ├── core │ │ ├── enums │ │ │ └── spawn_direction.dart │ │ ├── models │ │ │ ├── context_menu.dart │ │ │ ├── context_menu_entry.dart │ │ │ └── context_menu_item.dart │ │ └── utils │ │ │ ├── default_menu_shortcuts.dart │ │ │ ├── extensions.dart │ │ │ ├── helpers.dart │ │ │ ├── menu_route_options.dart │ │ │ ├── shortcuts │ │ │ ├── menu_item_shortcuts.dart │ │ │ └── menu_shortcuts.dart │ │ │ └── utils.dart │ │ ├── flutter_context_menu.dart │ │ └── widgets │ │ ├── context_menu_provider.dart │ │ ├── context_menu_region.dart │ │ ├── context_menu_state.dart │ │ ├── context_menu_widget.dart │ │ └── menu_entry_widget.dart ├── tips │ ├── tip.dart │ ├── tip.mapper.dart │ ├── tips_notifier.dart │ └── tips_page.dart ├── trios │ ├── app_state.dart │ ├── constants.dart │ ├── context_menu_items.dart │ ├── data_cache │ │ └── enabled_mods.dart │ ├── download_manager │ │ ├── download_manager.dart │ │ ├── download_request.dart │ │ ├── download_status.dart │ │ ├── download_task.dart │ │ └── downloader.dart │ ├── drag_drop_handler.dart │ ├── mod_metadata.dart │ ├── mod_metadata.mapper.dart │ ├── mod_variants.dart │ ├── navigation.dart │ ├── navigation.mapper.dart │ ├── providers.dart │ ├── self_updater │ │ ├── script_generator.dart │ │ └── self_updater.dart │ ├── settings │ │ ├── app_settings_logic.dart │ │ ├── debug_section.dart │ │ ├── settings.dart │ │ ├── settings.mapper.dart │ │ └── settings_page.dart │ └── toasts │ │ ├── mod_added_toast.dart │ │ ├── mod_download_toast.dart │ │ └── toast_manager.dart ├── utils │ ├── csv_parse_utils.dart │ ├── dart_mappable_utils.dart │ ├── debouncer.dart │ ├── extensions.dart │ ├── generic_settings_manager.dart │ ├── generic_settings_notifier.dart │ ├── http_client.dart │ ├── logging.dart │ ├── map_diff.dart │ ├── network_util.dart │ ├── platform_paths.dart │ ├── platform_specific.dart │ ├── pretty_printer_custom.dart │ ├── relative_timestamp.dart │ ├── search.dart │ └── util.dart ├── vram_estimator │ ├── charts │ │ ├── bar_chart.dart │ │ └── pie_chart.dart │ ├── graphics_lib_config_provider.dart │ ├── image_reader │ │ ├── image_reader_async.dart │ │ ├── image_readers.dart │ │ └── png_chatgpt.dart │ ├── models │ │ ├── gpu_info.dart │ │ ├── graphics_lib_config.dart │ │ ├── graphics_lib_config.mapper.dart │ │ ├── graphics_lib_info.dart │ │ ├── graphics_lib_info.mapper.dart │ │ ├── graphics_lib_lunaconfig.dart │ │ ├── graphics_lib_lunaconfig.mapper.dart │ │ ├── vram_checker_models.dart │ │ └── vram_checker_models.mapper.dart │ ├── vram_checker_logic.dart │ ├── vram_estimator_manager.dart │ ├── vram_estimator_manager.mapper.dart │ └── vram_estimator_page.dart ├── weaponViewer │ ├── models │ │ ├── weapon.dart │ │ └── weapon.mapper.dart │ ├── weaponPageWispGrid.dart │ └── weaponsManager.dart └── widgets │ ├── MultiSplitViewMixin.dart │ ├── add_new_mods_button.dart │ ├── blur.dart │ ├── centered_widget_with_item_after.dart │ ├── changelog_viewer.dart │ ├── checkbox_with_label.dart │ ├── code.dart │ ├── compact_list_tile.dart │ ├── conditional_wrap.dart │ ├── dash_painter.dart │ ├── debug_info.dart │ ├── dense_button.dart │ ├── disable.dart │ ├── disable_if_cannot_write_game_folder.dart │ ├── disable_if_cannot_write_mods.dart │ ├── dotted_border.dart │ ├── download_progress_indicator.dart │ ├── dropdown_with_icon.dart │ ├── fancy_mod_tooltip_header.dart │ ├── file_card.dart │ ├── fixed_height_grid_item.dart │ ├── force_game_version_warning_dialog.dart │ ├── graph_radio_selector.dart │ ├── hoverable_row.dart │ ├── hoverable_widget.dart │ ├── lazy_indexed_stack.dart │ ├── mod_icon.dart │ ├── mod_type_icon.dart │ ├── moving_tooltip.dart │ ├── palette_generator_mixin.dart │ ├── post_update_toast.dart │ ├── refresh_mods_button.dart │ ├── restartable_app.dart │ ├── self_update_toast.dart │ ├── settings_group.dart │ ├── simple_data_row.dart │ ├── spinning_refresh_button.dart │ ├── stroke_text.dart │ ├── svg_image_icon.dart │ ├── tab_button.dart │ ├── text_link_button.dart │ ├── text_trios.dart │ ├── text_with_icon.dart │ ├── toolbar_checkbox_button.dart │ ├── tooltip_frame.dart │ ├── trios_app_icon.dart │ ├── trios_expansion_tile.dart │ ├── trios_radio_tile.dart │ ├── tristate_icon_button.dart │ ├── under_construction_overlay.dart │ └── wisp_adaptive_grid_view.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake └── runner │ ├── CMakeLists.txt │ ├── main.cc │ ├── my_application.cc │ └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements └── RunnerTests │ └── RunnerTests.swift ├── pubspec.lock ├── pubspec.yaml ├── readme_resources ├── chipper.png ├── dashboard.png ├── jre.png └── rules_reload.png ├── test ├── 7zip_test.dart ├── json_test.dart ├── libarchive_test.dart ├── mod_profiles_test.dart ├── version_sorting_test.dart └── widget_test.dart ├── trios.iml ├── update-trios └── TriOS_self_updater.sh └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # GitHub Copilot persisted chat sessions 5 | /copilot/chatSessions 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Code_Generation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/runConfigurations/main_dart__profiling_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "8495dee1fd4aacbe9de707e7581203232f591b2f" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 8495dee1fd4aacbe9de707e7581203232f591b2f 17 | base_revision: 8495dee1fd4aacbe9de707e7581203232f591b2f 18 | - platform: macos 19 | create_revision: 8495dee1fd4aacbe9de707e7581203232f591b2f 20 | base_revision: 8495dee1fd4aacbe9de707e7581203232f591b2f 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /Windows-zip-release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | python Windows-zip-release.py 3 | pause 4 | -------------------------------------------------------------------------------- /Windows-zip-release.py: -------------------------------------------------------------------------------- 1 | import os 2 | import zipfile 3 | 4 | def zip_dir(src_dir, zip_file, exclude_dirs): 5 | with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED) as zf: 6 | for root, dirs, files in os.walk(src_dir): 7 | # Skip excluded directories 8 | dirs[:] = [d for d in dirs if os.path.join(root, d) not in exclude_dirs] 9 | 10 | for file in files: 11 | file_path = os.path.join(root, file) 12 | relative_path = os.path.relpath(file_path, src_dir) 13 | zip_path = os.path.join('TriOS', relative_path) 14 | zf.write(file_path, zip_path) 15 | 16 | if __name__ == '__main__': 17 | src_dir = os.path.abspath('./build/windows/x64/runner/Release') 18 | zip_file = 'TriOS-Windows.zip' 19 | exclude_dirs = { 20 | os.path.abspath('./build/windows/x64/runner/Release/data/flutter_assets/assets/linux'), 21 | os.path.abspath('./build/windows/x64/runner/Release/data/flutter_assets/assets/macos'), 22 | } 23 | 24 | print(f'Creating {zip_file} excluding: {exclude_dirs}') 25 | zip_dir(src_dir, zip_file, exclude_dirs) 26 | print(f'{zip_file} created successfully.') 27 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | analyzer: 27 | plugins: 28 | - custom_lint 29 | 30 | exclude: [build/**, lib/**.freezed.dart, lib/**.g.dart,lib/libarchive/libarchive_bindings.dart] 31 | # Additional information about this file can be found at 32 | # https://dart.dev/guides/language/analysis-options 33 | 34 | #formatter: 35 | # page_width: 80 -------------------------------------------------------------------------------- /assets/common/JpsAtHome.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/common/JpsAtHome.jar -------------------------------------------------------------------------------- /assets/fonts/Orbitron-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/fonts/Orbitron-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/Orbitron-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/fonts/Orbitron-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Orbitron-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/fonts/Orbitron-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Orbitron-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/fonts/Orbitron-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Orbitron-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/fonts/Orbitron-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Orbitron-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/fonts/Orbitron-SemiBold.ttf -------------------------------------------------------------------------------- /assets/images/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/images/arrow_down.png -------------------------------------------------------------------------------- /assets/images/arrow_down2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/images/arrow_down2.png -------------------------------------------------------------------------------- /assets/images/button_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/images/button_up.png -------------------------------------------------------------------------------- /assets/images/chipper/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/images/chipper/icon.png -------------------------------------------------------------------------------- /assets/images/construction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/images/construction.png -------------------------------------------------------------------------------- /assets/images/icon-account-box-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-admin-shield-half.svg: -------------------------------------------------------------------------------- 1 | shield-half-full -------------------------------------------------------------------------------- /assets/images/icon-admin-shield.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-archive-create.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-archive.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-arrow-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-arrow-split-vertical.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-arrow-up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-bookshelf.svg: -------------------------------------------------------------------------------- 1 | bookshelf -------------------------------------------------------------------------------- /assets/images/icon-broom.svg: -------------------------------------------------------------------------------- 1 | broom -------------------------------------------------------------------------------- /assets/images/icon-bullhorn-variant.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-clone.svg: -------------------------------------------------------------------------------- 1 | plus-box-multiple -------------------------------------------------------------------------------- /assets/images/icon-collapse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-console.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-dead.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-death-star.svg: -------------------------------------------------------------------------------- 1 | 12 | 13 | -------------------------------------------------------------------------------- /assets/images/icon-debug.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-dice.svg: -------------------------------------------------------------------------------- 1 | dice-multiple -------------------------------------------------------------------------------- /assets/images/icon-direct-install.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-discord-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/images/icon-donate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-done.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-drag-horizontal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-exclamation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-file-debug.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-file-history.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/icon-file-settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-folder-game.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-folder-mods.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-folder-multiple.svg: -------------------------------------------------------------------------------- 1 | folder-multiple -------------------------------------------------------------------------------- /assets/images/icon-folder-open.svg: -------------------------------------------------------------------------------- 1 | folder-open -------------------------------------------------------------------------------- /assets/images/icon-folder-saves.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-help-circled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-hide.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-ice-cream.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-image.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /assets/images/icon-incognito-circle.svg: -------------------------------------------------------------------------------- 1 | incognito -------------------------------------------------------------------------------- /assets/images/icon-info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-log.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-maximize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-menu-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/icon-more-horz.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-new-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-new-update.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-not-upcoming.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /assets/images/icon-open-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-open-in-app.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-open-in-new.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-package-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 37 | 38 | -------------------------------------------------------------------------------- /assets/images/icon-patreon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-podium-bronze.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-podium-gold.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-podium-silver.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-power.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-repair.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-save.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-show.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-shredder.svg: -------------------------------------------------------------------------------- 1 | shredder -------------------------------------------------------------------------------- /assets/images/icon-skip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-spider-web.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-stable.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-swap-upgrade.svg: -------------------------------------------------------------------------------- 1 | 2 | swap-vertical-bold 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/icon-swap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-tag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-target.svg: -------------------------------------------------------------------------------- 1 | target-variant -------------------------------------------------------------------------------- /assets/images/icon-test-radioactive.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 18 | -------------------------------------------------------------------------------- /assets/images/icon-text-box-edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-text.svg: -------------------------------------------------------------------------------- 1 | text -------------------------------------------------------------------------------- /assets/images/icon-tips.svg: -------------------------------------------------------------------------------- 1 | lightbulb -------------------------------------------------------------------------------- /assets/images/icon-toolbox.svg: -------------------------------------------------------------------------------- 1 | toolbox -------------------------------------------------------------------------------- /assets/images/icon-traffic-cone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-trash.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-update-badge.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-utility-mod.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-view-carousel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-vram-impact.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/images/icon-web.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-weight.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon-yawn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/telos_faction_crest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/images/telos_faction_crest.png -------------------------------------------------------------------------------- /assets/linux/7zip/arm64/7zzs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/7zip/arm64/7zzs -------------------------------------------------------------------------------- /assets/linux/7zip/x64/7zzs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/7zip/x64/7zzs -------------------------------------------------------------------------------- /assets/linux/libarchive/bin/bsdcat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/libarchive/bin/bsdcat -------------------------------------------------------------------------------- /assets/linux/libarchive/bin/bsdcpio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/libarchive/bin/bsdcpio -------------------------------------------------------------------------------- /assets/linux/libarchive/bin/bsdtar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/libarchive/bin/bsdtar -------------------------------------------------------------------------------- /assets/linux/libarchive/bin/bsdunzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/libarchive/bin/bsdunzip -------------------------------------------------------------------------------- /assets/linux/libarchive/lib/libarchive.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/libarchive/lib/libarchive.a -------------------------------------------------------------------------------- /assets/linux/libarchive/lib/libarchive.la: -------------------------------------------------------------------------------- 1 | # libarchive.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.7 Debian-2.4.7-7build1 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libarchive.so.13' 9 | 10 | # Names of this library. 11 | library_names='libarchive.so.13.7.5 libarchive.so.13 libarchive.so' 12 | 13 | # The name of the static archive. 14 | old_library='libarchive.a' 15 | 16 | # Linker flags that cannot go in dependency_libs. 17 | inherited_linker_flags='' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -llzma -lzstd -lbz2 -lz -lxml2' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libarchive. 26 | current=20 27 | age=7 28 | revision=5 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/usr/local/lib' 42 | -------------------------------------------------------------------------------- /assets/linux/libarchive/lib/libarchive.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/linux/libarchive/lib/libarchive.so -------------------------------------------------------------------------------- /assets/linux/libarchive/lib/pkgconfig/libarchive.pc: -------------------------------------------------------------------------------- 1 | prefix=/home/david/libarchve-output 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: libarchive 7 | Description: library that can create and read several streaming archive formats 8 | Version: 3.7.5 9 | Cflags: -I${includedir} 10 | Cflags.private: -DLIBARCHIVE_STATIC 11 | Libs: -L${libdir} -larchive 12 | Libs.private: -llzma -lzstd -lbz2 -lz -lxml2 13 | Requires.private: libcrypto 14 | -------------------------------------------------------------------------------- /assets/macos/7zip/7zz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/7zip/7zz -------------------------------------------------------------------------------- /assets/macos/libarchive/bin/bsdcat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/bin/bsdcat -------------------------------------------------------------------------------- /assets/macos/libarchive/bin/bsdcpio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/bin/bsdcpio -------------------------------------------------------------------------------- /assets/macos/libarchive/bin/bsdtar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/bin/bsdtar -------------------------------------------------------------------------------- /assets/macos/libarchive/bin/bsdunzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/bin/bsdunzip -------------------------------------------------------------------------------- /assets/macos/libarchive/lib/libarchive.13.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/lib/libarchive.13.dylib -------------------------------------------------------------------------------- /assets/macos/libarchive/lib/libarchive.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/lib/libarchive.a -------------------------------------------------------------------------------- /assets/macos/libarchive/lib/libarchive.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/macos/libarchive/lib/libarchive.dylib -------------------------------------------------------------------------------- /assets/macos/libarchive/lib/libarchive.la: -------------------------------------------------------------------------------- 1 | # libarchive.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.7 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libarchive.13.dylib' 9 | 10 | # Names of this library. 11 | library_names='libarchive.13.dylib libarchive.dylib' 12 | 13 | # The name of the static archive. 14 | old_library='libarchive.a' 15 | 16 | # Linker flags that cannot go in dependency_libs. 17 | inherited_linker_flags=' ' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -liconv -llzma -lbz2 -lz -lxml2' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libarchive. 26 | current=20 27 | age=7 28 | revision=5 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/Users/davidwhitman/libarchve-output/lib' 42 | -------------------------------------------------------------------------------- /assets/macos/libarchive/lib/pkgconfig/libarchive.pc: -------------------------------------------------------------------------------- 1 | prefix=/Users/davidwhitman/libarchve-output 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: libarchive 7 | Description: library that can create and read several streaming archive formats 8 | Version: 3.7.5 9 | Cflags: -I${includedir} 10 | Cflags.private: -DLIBARCHIVE_STATIC 11 | Libs: -L${libdir} -larchive 12 | Libs.private: -llzma -lbz2 -lz -lxml2 13 | Requires.private: iconv 14 | -------------------------------------------------------------------------------- /assets/windows/7zip/7-zip.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/7-zip.dll -------------------------------------------------------------------------------- /assets/windows/7zip/7z.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/7z.dll -------------------------------------------------------------------------------- /assets/windows/7zip/7z.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/7z.exe -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/LICENSE: -------------------------------------------------------------------------------- 1 | 7-Zip source code 2 | ~~~~~~~~~~~~~~~~~ 3 | License for use and distribution 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | 7-Zip Codecs Copyright (C) 2016 - 2023 Tino Reichardt. 7 | 8 | 9 | GNU LGPL information 10 | -------------------- 11 | 12 | This library is free software; you can redistribute it and/or 13 | modify it under the terms of the GNU Lesser General Public 14 | License as published by the Free Software Foundation; either 15 | version 2.1 of the License, or (at your option) any later version. 16 | 17 | This library is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with this library; if not, write to the Free Software 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 | 26 | -- 27 | Tino Reichardt 28 | -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/README.md: -------------------------------------------------------------------------------- 1 | 2 | This archive contains two precompiled DLL's for 7-Zip v17.00 or higher. 3 | 4 | ## Installation 5 | 6 | 1. download the codec archiv from https://mcmilk.de/projects/7-Zip-zstd/ 7 | 2. create a new directory named "Codecs" 8 | 3. put in there the files of the Codecs-ARCH.7z archiv to your Installation 9 | - normally, the x32 should go to: "C:\Program Files (x86)\7-Zip\Codecs" 10 | - x64: version should go in here: "C:\Program Files\7-Zip\Codecs" 11 | 12 | ## Usage 13 | 14 | - when compressing binaries (*.exe, *.dll), you have to explicitly disable 15 | the bcj2 filter via `-m0=bcj` 16 | - so the usage should look like this: 17 | 18 | ``` 19 | 7z a archiv.7z -m0=bcj -m1=zstd -mx1 ...Fast mode, with BCJ preprocessor on executables 20 | 7z a archiv.7z -m0=bcj -m1=zstd -mx.. ... 21 | 7z a archiv.7z -m0=bcj -m1=zstd -mx21 ...2nd Slowest Mode, with BCJ preprocessor on executables 22 | 7z a archiv.7z -m0=bcj -m1=zstd -mx22 ...Ultra Mode, with BCJ preprocessor on executables 23 | ``` 24 | 25 | ## License and redistribution 26 | 27 | - the same as the original 7-Zip, which means GNU LGPL 28 | -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/brotli.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/Codecs/brotli.dll -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/flzma2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/Codecs/flzma2.dll -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/lizard.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/Codecs/lizard.dll -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/lz4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/Codecs/lz4.dll -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/lz5.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/Codecs/lz5.dll -------------------------------------------------------------------------------- /assets/windows/7zip/Codecs/zstd.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/7zip/Codecs/zstd.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/archive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/archive.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/bz2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/bz2.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/iconv-2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/iconv-2.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/libcrypto-3-x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/libcrypto-3-x64.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/liblzma.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/liblzma.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/libxml2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/libxml2.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/lz4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/lz4.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/zlib1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/zlib1.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/bin/zstd.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/bin/zstd.dll -------------------------------------------------------------------------------- /assets/windows/libarchive/lib/archive.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/lib/archive.lib -------------------------------------------------------------------------------- /assets/windows/libarchive/lib/archive_static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/assets/windows/libarchive/lib/archive_static.lib -------------------------------------------------------------------------------- /assets/windows/libarchive/lib/pkgconfig/libarchive.pc: -------------------------------------------------------------------------------- 1 | prefix=C:/Program Files (x86)/libarchive 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: libarchive 7 | Description: library that can create and read several streaming archive formats 8 | Version: 3.7.5 9 | Cflags: -I${includedir} 10 | Cflags.private: -DLIBARCHIVE_STATIC 11 | Libs: -L${libdir} -larchive 12 | Libs.private: -loptimized -lzlib -ldebug -lzlibd -lbz2 -lbz2d -llzma -llzma -llz4 -lzstd -lbcrypt -lcrypto -lcrypto -liconv -lcharset -lxml2 -lxml2 -lssl -lssl 13 | Requires.private: 14 | -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | dart_json_mapper: 5 | options: 6 | build_extensions: 7 | '^lib/{{}}.dart': 'lib/generated/{{}}.g.dart' 8 | generate_for: 9 | # here should be listed entry point files having 'void main()' function 10 | - lib/main.dart 11 | 12 | # This part is needed to tell original reflectable builder to stay away 13 | # it overrides default options for reflectable builder to an **empty** set of files 14 | # reflectable: 15 | # generate_for: 16 | # - no/files 17 | 18 | source_gen|combining_builder: 19 | options: 20 | build_extensions: 21 | '^lib/{{}}.dart': 'lib/generated/{{}}.g.dart' 22 | 23 | # bugged: https://github.com/schultek/dart_mappable/issues/192 24 | # dart_mappable_builder: 25 | # options: 26 | # build_extensions: 27 | # '^lib/{{}}.dart': 28 | # - 'lib/generated/{{}}.mapper.dart' 29 | # - 'lib/generated/{{}}.init.dart' -------------------------------------------------------------------------------- /build_bit7z_bindings.yaml: -------------------------------------------------------------------------------- 1 | # Usage: `dart run ffigen --config build_bit7z_bindings.yaml` 2 | 3 | name: Bit7zBinding 4 | output: lib/bit7z/bit7z_bindings.dart 5 | headers: 6 | entry-points: 7 | - assets/windows/bit7z/include/bit7z/bitfileextractor.hpp 8 | - assets/windows/bit7z/include/bit7z/bitarchivereader.hpp 9 | 10 | -------------------------------------------------------------------------------- /build_libarchive_bindings.yaml: -------------------------------------------------------------------------------- 1 | # Usage: `dart run ffigen --config build_libarchive_bindings.yaml` 2 | 3 | name: LibArchiveBinding 4 | output: lib/libarchive/libarchive_bindings.dart 5 | headers: 6 | entry-points: 7 | - assets/libarchive/windows/include/archive.h 8 | - assets/libarchive/windows/include/archive_entry.h 9 | 10 | -------------------------------------------------------------------------------- /devtools_options.yaml: -------------------------------------------------------------------------------- 1 | description: This file stores settings for Dart & Flutter DevTools. 2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states 3 | extensions: 4 | -------------------------------------------------------------------------------- /lib/catalog/mod_browser_manager.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter_cache_manager/flutter_cache_manager.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:http/http.dart' as http; 4 | import 'package:trios/catalog/models/scraped_mod.dart'; 5 | import 'package:trios/trios/constants.dart'; 6 | import 'package:trios/utils/logging.dart'; 7 | 8 | final isLoadingCatalog = StateProvider((ref) => false); 9 | 10 | final browseModsNotifierProvider = StreamProvider(( 11 | ref, 12 | ) async* { 13 | final currentTime = DateTime.now(); 14 | ref.watch(isLoadingCatalog.notifier).state = true; 15 | // final cache = CacheManager(Config("trios_modrepo_cache")); 16 | String modRepo; 17 | 18 | try { 19 | // final cache = CacheManager(Config("trios_modrepo_cache")); 20 | modRepo = (await http.get(Uri.parse(Constants.modRepoUrl))).body; 21 | // (await cache.getSingleFile(Constants.modRepoUrl)).readAsStringSync(); 22 | } catch (ex, st) { 23 | Fimber.w('Failed to fetch mod repo', ex: ex, stacktrace: st); 24 | ref.watch(isLoadingCatalog.notifier).state = false; 25 | // cache.emptyCache(); 26 | return; 27 | } 28 | 29 | try { 30 | final scrapedMods = ScrapedModsRepoMapper.fromJson((modRepo).toString()); 31 | 32 | ref.watch(isLoadingCatalog.notifier).state = false; 33 | Fimber.i( 34 | 'Parsed ${scrapedMods.items.length} scraped mods in ${DateTime.now().difference(currentTime).inMilliseconds}ms', 35 | ); 36 | 37 | yield scrapedMods; 38 | } catch (ex, st) { 39 | Fimber.w('Failed to parse mod repo', ex: ex, stacktrace: st); 40 | ref.watch(isLoadingCatalog.notifier).state = false; 41 | return; 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /lib/chipper/copy.dart: -------------------------------------------------------------------------------- 1 | import 'chipper_state.dart'; 2 | 3 | String createSystemCopyString(LogChips? chips) => 4 | "Game: ${chips?.gameVersion ?? "Not found in log."}\nJava: ${chips?.javaVersion ?? "Not found in log."}\nOS: ${chips?.os ?? "Not found in log."}"; 5 | 6 | String createModsCopyString(LogChips? chips, {bool minify = false}) => 7 | "Mods (${chips?.modList.modList.length})\n${chips?.modList.modList.map((e) => minify ? "${e.modId} ${e.modVersion}" : "${e.modName} v${e.modVersion} [${e.modId}]").join('\n')}"; 8 | 9 | String createErrorsCopyString(LogChips? chips) => 10 | "Line: Error message\n${chips?.errorBlock.map((e) => "${e.lineNumber}: ${e.fullError}").join('\n')}"; 11 | -------------------------------------------------------------------------------- /lib/chipper/models/user_mods.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | 3 | import 'mod_entry.dart'; 4 | 5 | class UserMods { 6 | UnmodifiableListView modList; 7 | bool isPerfectList; 8 | 9 | UserMods(this.modList, {required this.isPerfectList}); 10 | } 11 | -------------------------------------------------------------------------------- /lib/chipper/views/wavy_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math'; 3 | 4 | class WavyLinePainter extends CustomPainter { 5 | final Color lineColor; 6 | final double lineHeight; 7 | final double dashWidth; 8 | final double dashSpace; 9 | 10 | WavyLinePainter({ 11 | this.lineColor = Colors.black, 12 | this.lineHeight = 50.0, 13 | this.dashWidth = 10.0, 14 | this.dashSpace = 5.0, 15 | }); 16 | 17 | @override 18 | void paint(Canvas canvas, Size size) { 19 | final paint = Paint() 20 | ..color = lineColor 21 | ..style = PaintingStyle.stroke 22 | ..strokeWidth = 1.0; 23 | 24 | final path = Path(); 25 | path.moveTo(0, lineHeight); 26 | 27 | for (int i = 0; i < size.width; i++) { 28 | path.lineTo(i.toDouble(), lineHeight + sin(i * 0.1) * 0); 29 | } 30 | 31 | _drawDashedLine(canvas, path, dashWidth, dashSpace, paint); 32 | } 33 | 34 | void _drawDashedLine( 35 | Canvas canvas, 36 | Path path, 37 | double dashWidth, 38 | double dashSpace, 39 | Paint paint, 40 | ) { 41 | var pathMetrics = path.computeMetrics(); 42 | for (var metric in pathMetrics) { 43 | for (double i = 0.0; i < metric.length; i += dashWidth + dashSpace) { 44 | final extractPath = metric.extractPath(i, i + dashWidth); 45 | canvas.drawPath(extractPath, paint); 46 | } 47 | } 48 | } 49 | 50 | @override 51 | bool shouldRepaint(CustomPainter oldDelegate) => false; 52 | } 53 | 54 | class WavyLineWidget extends StatelessWidget { 55 | final Color color; 56 | final double height; 57 | 58 | const WavyLineWidget({ 59 | super.key, 60 | this.color = Colors.black, 61 | this.height = 1.0, 62 | }); 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return CustomPaint( 67 | painter: WavyLinePainter(lineColor: color, lineHeight: height), 68 | child: Container(height: height), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/mod_manager/copy_mod_list_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:trios/mod_manager/mod_manager_logic.dart'; 3 | import 'package:trios/models/mod.dart'; 4 | import 'package:trios/widgets/moving_tooltip.dart'; 5 | 6 | class CopyModListButtonLarge extends StatelessWidget { 7 | const CopyModListButtonLarge({ 8 | super.key, 9 | required this.mods, 10 | required this.enabledMods, 11 | }); 12 | 13 | final List mods; 14 | final List enabledMods; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return MovingTooltipWidget.text( 19 | message: "Copy mod list to clipboard\n\nRight-click for ALL mods", 20 | child: Padding( 21 | padding: const EdgeInsets.only(left: 4, top: 4, bottom: 4), 22 | child: GestureDetector( 23 | onSecondaryTap: () { 24 | copyModListToClipboardFromMods(mods, context); 25 | }, 26 | child: OutlinedButton.icon( 27 | onPressed: () => 28 | copyModListToClipboardFromMods(enabledMods, context), 29 | label: const Text("Copy"), 30 | style: OutlinedButton.styleFrom( 31 | foregroundColor: Theme.of( 32 | context, 33 | ).colorScheme.onSurface.withOpacity(0.8), 34 | side: BorderSide( 35 | color: Theme.of(context).colorScheme.onSurface.withOpacity(0.8), 36 | ), 37 | ), 38 | icon: const Icon(Icons.copy, size: 20), 39 | ), 40 | ), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/mod_manager/filter_mods_search_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:trios/mod_manager/mods_grid_page.dart'; 4 | 5 | class FilterModsSearchBar extends StatelessWidget { 6 | const FilterModsSearchBar({ 7 | super.key, 8 | required this.searchController, 9 | required this.query, 10 | required this.ref, 11 | }); 12 | 13 | final SearchController searchController; 14 | final String query; 15 | final WidgetRef ref; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return SearchAnchor( 20 | searchController: searchController, 21 | builder: (BuildContext context, SearchController controller) { 22 | return SearchBar( 23 | controller: controller, 24 | leading: const Icon(Icons.search), 25 | hintText: "Filter...", 26 | trailing: [ 27 | query.isEmpty 28 | ? Container() 29 | : IconButton( 30 | icon: const Icon(Icons.clear), 31 | constraints: const BoxConstraints(), 32 | padding: EdgeInsets.zero, 33 | onPressed: () { 34 | controller.clear(); 35 | ref.read(modsGridSearchQuery.notifier).state = ""; 36 | }, 37 | ), 38 | ], 39 | backgroundColor: WidgetStateProperty.all( 40 | Theme.of(context).colorScheme.surfaceContainer, 41 | ), 42 | onChanged: (value) { 43 | ref.read(modsGridSearchQuery.notifier).state = value; 44 | }, 45 | ); 46 | }, 47 | suggestionsBuilder: (BuildContext context, SearchController controller) { 48 | return []; 49 | }, 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/models/download_progress.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | 3 | part 'download_progress.mapper.dart'; 4 | 5 | @MappableClass() 6 | class TriOSDownloadProgress with TriOSDownloadProgressMappable { 7 | final int bytesReceived; 8 | final int bytesTotal; 9 | final bool isIndeterminate; 10 | final String? customStatus; 11 | 12 | const TriOSDownloadProgress( 13 | this.bytesReceived, 14 | this.bytesTotal, { 15 | this.isIndeterminate = false, 16 | this.customStatus, 17 | }); 18 | 19 | double get progressPercent => (bytesReceived / bytesTotal).clamp(0, 1); 20 | 21 | /// Aggregates multiple `TriOSDownloadProgress` objects into a single one. 22 | /// - Sums `bytesReceived` and `bytesTotal`. 23 | /// - Sets `isIndeterminate` to `true` if **any** progress is indeterminate. 24 | /// - For `customStatus`, you could: 25 | /// - Use the first non-null, 26 | /// - Combine them, 27 | /// - Or omit it. 28 | /// Adjust to your needs. 29 | static TriOSDownloadProgress? aggregate( 30 | Iterable progressList, 31 | ) { 32 | if (progressList.isEmpty) { 33 | return null; 34 | } 35 | 36 | final totalReceived = progressList.fold( 37 | 0, 38 | (sum, p) => sum + p.bytesReceived, 39 | ); 40 | final totalBytes = progressList.fold( 41 | 0, 42 | (sum, p) => sum + p.bytesTotal, 43 | ); 44 | final anyIndeterminate = progressList.any((p) => p.isIndeterminate); 45 | 46 | // Show first non-null custom status 47 | final firstNonNullStatus = progressList 48 | .map((p) => p.customStatus) 49 | .firstWhere((s) => s != null, orElse: () => null); 50 | 51 | return TriOSDownloadProgress( 52 | totalReceived, 53 | totalBytes, 54 | isIndeterminate: anyIndeterminate, 55 | customStatus: firstNonNullStatus, 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/models/enabled_mods.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | import 'package:trios/models/mod.dart'; 3 | 4 | part 'enabled_mods.mapper.dart'; 5 | 6 | @MappableClass() 7 | class EnabledMods with EnabledModsMappable { 8 | final Set enabledMods; 9 | 10 | const EnabledMods(this.enabledMods); 11 | 12 | /// Returns only the mod ids that are in both the `enabled_mods.json` file and the provided mod list. 13 | EnabledMods filterOutMissingMods(List mods) { 14 | return EnabledMods( 15 | enabledMods 16 | .where((enabledModId) => mods.any((mod) => mod.id == enabledModId)) 17 | .toSet(), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/models/launch_settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | 3 | part 'launch_settings.mapper.dart'; 4 | 5 | @MappableClass() 6 | class LaunchSettings with LaunchSettingsMappable { 7 | final bool? isFullscreen; 8 | final bool? hasSound; 9 | final int? resolutionWidth; 10 | final int? resolutionHeight; 11 | final int? numAASamples; 12 | final double? screenScaling; 13 | 14 | const LaunchSettings({ 15 | this.isFullscreen, 16 | this.hasSound, 17 | this.resolutionWidth, 18 | this.resolutionHeight, 19 | this.numAASamples, 20 | this.screenScaling, 21 | }); 22 | 23 | /// Overrides the current settings with values from another instance. 24 | LaunchSettings overrideWith(LaunchSettings? other) { 25 | return LaunchSettings( 26 | isFullscreen: other?.isFullscreen ?? isFullscreen, 27 | hasSound: other?.hasSound ?? hasSound, 28 | resolutionWidth: other?.resolutionWidth ?? resolutionWidth, 29 | resolutionHeight: other?.resolutionHeight ?? resolutionHeight, 30 | numAASamples: other?.numAASamples ?? numAASamples, 31 | screenScaling: other?.screenScaling ?? screenScaling, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/models/mod_info.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_mappable/dart_mappable.dart'; 4 | import 'package:trios/models/mod_variant.dart'; 5 | import 'package:trios/models/version.dart'; 6 | 7 | import '../utils/dart_mappable_utils.dart'; 8 | import 'mod_info_json.dart'; 9 | 10 | part 'mod_info.mapper.dart'; 11 | 12 | // TODO should prob merge this into ModInfoJson 13 | @MappableClass() 14 | class ModInfo with ModInfoMappable { 15 | final String id; 16 | final String? name; 17 | @MappableField(hook: VersionHook()) 18 | final Version? version; 19 | final String? description; 20 | final String? gameVersion; 21 | final String? author; 22 | final List dependencies; 23 | final String? originalGameVersion; 24 | final bool isUtility; 25 | final bool isTotalConversion; 26 | 27 | ModInfo({ 28 | required this.id, 29 | this.name, 30 | this.version, 31 | this.description, 32 | this.gameVersion, 33 | this.author, 34 | this.dependencies = const [], 35 | this.originalGameVersion, 36 | this.isUtility = false, 37 | this.isTotalConversion = false, 38 | }); 39 | 40 | // Factory method to create a ModInfo from a ModInfoJson model 41 | factory ModInfo.fromJsonModel(ModInfoJson model, Directory modFolder) => 42 | ModInfo( 43 | id: model.id, 44 | name: model.name, 45 | version: model.version, 46 | author: model.author, 47 | description: model.description, 48 | gameVersion: model.gameVersion, 49 | dependencies: model.dependencies, 50 | originalGameVersion: model.originalGameVersion, 51 | isUtility: model.utility, 52 | isTotalConversion: model.totalConversion, 53 | ); 54 | 55 | // TODO swap this to id, change id to modId. 56 | String get smolId => createSmolId(id, version); 57 | String get nameOrId => name ?? id; 58 | String get formattedNameVersionId => 59 | "$name${version != null ? " $version" : ""}${" ($id)"}"; 60 | String get formattedNameVersion => 61 | "$nameOrId${version != null ? " $version" : ""}"; 62 | } 63 | -------------------------------------------------------------------------------- /lib/models/version_checker_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | import 'package:trios/models/mod_info_json.dart'; 3 | import 'package:trios/utils/util.dart'; 4 | 5 | part 'version_checker_info.mapper.dart'; 6 | 7 | @MappableClass() 8 | class VersionCheckerInfo with VersionCheckerInfoMappable { 9 | final String? modName; 10 | final String? masterVersionFile; 11 | final String? modNexusId; 12 | final String? modThreadId; 13 | final VersionObject? modVersion; 14 | final String? directDownloadURL; 15 | final String? changelogURL; 16 | 17 | VersionCheckerInfo({ 18 | this.modName, 19 | this.masterVersionFile, 20 | this.modNexusId, 21 | this.modThreadId, 22 | this.modVersion, 23 | this.directDownloadURL, 24 | this.changelogURL, 25 | }); 26 | 27 | /// Whether there's a valid direct download URL. 28 | bool get hasDirectDownload => 29 | directDownloadURL != null && 30 | directDownloadURL!.isNotEmpty && 31 | Uri.tryParse(directDownloadURL!) != null; 32 | 33 | /// Whether the basic fields are present and ostensibly valid. 34 | bool get seemsLegit => 35 | masterVersionFile != null && 36 | masterVersionFile!.isNotEmpty && 37 | Uri.tryParse(masterVersionFile!) != null && 38 | modVersion != null; 39 | } 40 | -------------------------------------------------------------------------------- /lib/shipViewer/models/ship.dart: -------------------------------------------------------------------------------- 1 | // import 'dart:ui'; 2 | // 3 | // import 'package:dart_extensions_methods/dart_extension_methods.dart'; 4 | // 5 | // import '../utils.dart'; 6 | // import 'shipCsv.dart'; 7 | // import 'shipJson.dart'; 8 | // 9 | // class OldShip { 10 | // String id; 11 | // Color color = const Color(0x00000000); 12 | // ShipCsv shipCsv; 13 | // ShipJson shipJson; 14 | // String? modId; 15 | // String? modName; 16 | // 17 | // Ship({required this.id, required this.shipCsv, required this.shipJson, required this.modId, required this.modName}) { 18 | // color = stringToColor(id); 19 | // } 20 | // 21 | // Set hintsSplitUppercase() => shipCsv.hints?.split(",").map((e) => e.trim().toUpperCase()).toSet() ?? {}; 22 | // 23 | // Set tagsSplitUppercase() => shipCsv.tags?.split(",").map((e) => e.trim().toUpperCase()).toSet() ?? {}; 24 | // 25 | // // tostring 26 | // @override 27 | // String toString() { 28 | // return 'Name: ${shipCsv.name} ($id)\nMod: ${modName ?? "(vanilla)"}${modId?.let((e) => " ($e)") ?? ""}\nCSV: $shipCsv\nJSON: $shipJson'; 29 | // } 30 | // } 31 | -------------------------------------------------------------------------------- /lib/shipViewer/models/shipEngineSlot.dart: -------------------------------------------------------------------------------- 1 | // import 'package:json_annotation/json_annotation.dart'; 2 | // 3 | // import 'shipEngineStyleSpec.dart'; 4 | // 5 | // part '../generated/models/shipEngineSlot.g.dart'; 6 | // 7 | // /// TStarfarerShipEngine 8 | // @JsonSerializable() 9 | // class EngineSlot { 10 | // final List? location; 11 | // final double length; 12 | // final double width; 13 | // final double angle; 14 | // final String style; 15 | // final String? styleId; 16 | // final EngineStyleSpec? styleSpec; 17 | // final double contrailSize; 18 | // 19 | // EngineSlot( 20 | // {this.location, 21 | // this.length = 0, 22 | // this.width = 0, 23 | // this.angle = 0, 24 | // this.style = "", 25 | // this.styleId = "", 26 | // this.styleSpec, 27 | // this.contrailSize = 0}); 28 | // 29 | // /// Connect the generated function to the `fromJson` 30 | // /// factory. 31 | // factory EngineSlot.fromJson(Map json) => _$EngineSlotFromJson(json); 32 | // 33 | // /// Connect the generated function to the `toJson` method. 34 | // Map toJson() => _$EngineSlotToJson(this); 35 | // 36 | // @override 37 | // String toString() { 38 | // return 'EngineSlot{location: $location, length: $length, width: $width, angle: $angle, style: $style, styleId: $styleId, styleSpec: $styleSpec, contrailSize: $contrailSize}'; 39 | // } 40 | // } 41 | -------------------------------------------------------------------------------- /lib/shipViewer/models/shipEngineSlotChange.dart: -------------------------------------------------------------------------------- 1 | // import 'package:freezed_annotation/freezed_annotation.dart'; 2 | // 3 | // import 'shipEngineStyleSpec.dart'; 4 | // 5 | // part '../generated/models/shipEngineSlotChange.freezed.dart'; 6 | // part '../generated/models/shipEngineSlotChange.g.dart'; 7 | // 8 | // /// TStarfarerShipEngineChange 9 | // @freezed 10 | // sealed class ShipEngineSlotChange with _$ShipEngineSlotChange { 11 | // factory ShipEngineSlotChange({ 12 | // final List? location, 13 | // final double? length, 14 | // final double? width, 15 | // final double? angle, 16 | // final String? style, 17 | // final String? styleId, 18 | // final EngineStyleSpec? styleSpec, 19 | // final double? contrailSize, 20 | // }) = _ShipEngineSlotChange; 21 | // 22 | // factory ShipEngineSlotChange.fromJson(Map json) => _$ShipEngineSlotChangeFromJson(json); 23 | // 24 | // // Map toJson() => _$ShipEngineSlotChangeToJson(this); 25 | // } 26 | -------------------------------------------------------------------------------- /lib/shipViewer/models/shipEngineStyleSpec.dart: -------------------------------------------------------------------------------- 1 | // import 'package:json_annotation/json_annotation.dart'; 2 | // 3 | // part '../generated/models/shipEngineStyleSpec.g.dart'; 4 | // 5 | // @JsonSerializable() 6 | // class EngineStyleSpec { 7 | // final String type; 8 | // final String mode; 9 | // final List? engineColor; 10 | // final List? engineCampaignColor; 11 | // final double contrailParticleSizeMult; 12 | // final double contrailParticleFinalSizeMult; 13 | // final double contrailParticleDuration; 14 | // final double contrailMaxSpeedMult; 15 | // final double contrailAngularVelocityMult; 16 | // final List? contrailColor; 17 | // final List? contrailCampaignColor; 18 | // 19 | // EngineStyleSpec( 20 | // {this.type = "", 21 | // this.mode = "", 22 | // this.engineColor, 23 | // this.engineCampaignColor, 24 | // this.contrailParticleSizeMult = 0, 25 | // this.contrailParticleFinalSizeMult = 0, 26 | // this.contrailParticleDuration = 0, 27 | // this.contrailMaxSpeedMult = 0, 28 | // this.contrailAngularVelocityMult = 0, 29 | // this.contrailColor, 30 | // this.contrailCampaignColor}); 31 | // 32 | // /// Connect the generated function to the `fromJson` 33 | // /// factory. 34 | // factory EngineStyleSpec.fromJson(Map json) => _$EngineStyleSpecFromJson(json); 35 | // 36 | // /// Connect the generated function to the `toJson` method. 37 | // Map toJson() => _$EngineStyleSpecToJson(this); 38 | // 39 | // @override 40 | // String toString() { 41 | // return 'EngineStyleSpec{type: $type, mode: $mode, engineColor: $engineColor, engineCampaignColor: $engineCampaignColor, contrailParticleSizeMult: $contrailParticleSizeMult, contrailParticleFinalSizeMult: $contrailParticleFinalSizeMult, contrailParticleDuration: $contrailParticleDuration, contrailMaxSpeedMult: $contrailMaxSpeedMult, contrailAngularVelocityMult: $contrailAngularVelocityMult, contrailColor: $contrailColor, contrailCampaignColor: $contrailCampaignColor}'; 42 | // } 43 | // } 44 | -------------------------------------------------------------------------------- /lib/shipViewer/models/shipWeaponSlotChange.dart: -------------------------------------------------------------------------------- 1 | // import 'package:freezed_annotation/freezed_annotation.dart'; 2 | // 3 | // part '../generated/models/shipWeaponSlotChange.freezed.dart'; 4 | // part '../generated/models/shipWeaponSlotChange.g.dart'; 5 | // 6 | // /// TStarfarerShipWeaponChange 7 | // @freezed 8 | // sealed class ShipWeaponSlotChange with _$ShipWeaponSlotChange { 9 | // factory ShipWeaponSlotChange( 10 | // {final double? angle, 11 | // final double? arc, 12 | // final String? id, 13 | // final List? locations, 14 | // final List? position, 15 | // final String? mount, 16 | // final String? size, 17 | // final String? type, 18 | // final double? renderOrderMod}) = _ShipWeaponSlotChange; 19 | // 20 | // factory ShipWeaponSlotChange.fromJson(Map json) => _$ShipWeaponSlotChangeFromJson(json); 21 | // 22 | // // Map toJson() => _$ShipWeaponSlotChangeToJson(this); 23 | // 24 | // @override 25 | // String toString() { 26 | // return 'ShipWeaponSlotChange{angle: $angle, arc: $arc, id: $id, locations: $locations, position: $position, mount: $mount, size: $size, type: $type, renderOrderMod: $renderOrderMod}'; 27 | // } 28 | // } 29 | -------------------------------------------------------------------------------- /lib/shipViewer/models/ship_weapon_slot.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | 3 | part 'ship_weapon_slot.mapper.dart'; 4 | 5 | @MappableClass() 6 | class ShipWeaponSlot with ShipWeaponSlotMappable { 7 | final double angle; 8 | final double arc; 9 | final String id; 10 | final List locations; 11 | final List position; 12 | final String mount; 13 | final String size; 14 | final String type; 15 | final double? renderOrderMod; 16 | 17 | const ShipWeaponSlot({ 18 | this.angle = 0, 19 | this.arc = 0, 20 | this.id = '', 21 | this.locations = const [], 22 | this.position = const [], 23 | this.mount = '', 24 | this.size = '', 25 | this.type = '', 26 | this.renderOrderMod, 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /lib/shipViewer/models/variant.dart: -------------------------------------------------------------------------------- 1 | // import 'package:freezed_annotation/freezed_annotation.dart'; 2 | // 3 | // import 'converters/alexMapConverter.dart'; 4 | // import 'variantWeapon.dart'; 5 | // 6 | // part '../generated/models/variant.freezed.dart'; 7 | // part '../generated/models/variant.g.dart'; 8 | // 9 | // @freezed 10 | // sealed class Variant with _$Variant { 11 | // factory Variant({ 12 | // @Default("New Variant") final String displayName, 13 | // @Default("") final String hullId, 14 | // @Default("") final String variantId, 15 | // @Default(0) final int fluxVents, 16 | // @Default(0) final int fluxCapacitors, 17 | // @Default([]) final List hullMods, 18 | // @Default([]) final List weaponGroups, 19 | // @Default(false) final bool goalVariant, 20 | // @Default(1.0) final double quality, 21 | // @Default([]) final List permaMods, 22 | // @Default([]) final List wings, 23 | // @AlexMapConverter() @Default({}) final Map modules, 24 | // }) = _Variant; 25 | // 26 | // factory Variant.fromJson(Map json) => _$VariantFromJson(json); 27 | // } 28 | -------------------------------------------------------------------------------- /lib/shipViewer/models/variantWeapon.dart: -------------------------------------------------------------------------------- 1 | // import 'package:freezed_annotation/freezed_annotation.dart'; 2 | // 3 | // part '../generated/models/variantWeapon.freezed.dart'; 4 | // part '../generated/models/variantWeapon.g.dart'; 5 | // 6 | // @freezed 7 | // sealed class VariantWeapon with _$VariantWeapon { 8 | // factory VariantWeapon({ 9 | // @Default(false) final bool autofire, 10 | // @Default("") final String mode, 11 | // @Default({}) final Map weapons, 12 | // }) = _VariantWeapon; 13 | // 14 | // factory VariantWeapon.fromJson(Map json) => _$VariantWeaponFromJson(json); 15 | // } 16 | -------------------------------------------------------------------------------- /lib/thirdparty/dartx/arithmetic.dart: -------------------------------------------------------------------------------- 1 | extension NumArithmeticX on T { 2 | /// Minus val if if it not null else returns `this` 3 | T? minus(T? val) => val == null ? this : this - val as T?; 4 | 5 | /// returns null if val is null else returns `this` - val 6 | T? minusOrNull(T? val) => val == null ? null : this - val as T?; 7 | 8 | /// Adds val if if it not null else returns `this` 9 | T? plus(T? val) => val == null ? this : this + val as T?; 10 | 11 | /// returns null if val is null else returns `this` + val 12 | T? plusOrNull(T? val) => val == null ? null : this + val as T?; 13 | } 14 | -------------------------------------------------------------------------------- /lib/thirdparty/dartx/comparator.dart: -------------------------------------------------------------------------------- 1 | extension CompararatorComposeExtensions on Comparator { 2 | /// return a new comparator, 3 | /// that sorts the items first by the criteria of this comparator, 4 | /// then by the criteria of the given comparator 5 | Comparator compose(Comparator then) { 6 | return (a, b) { 7 | final first = this(a, b); 8 | if (first != 0) { 9 | return first; 10 | } 11 | return then(a, b); 12 | }; 13 | } 14 | } 15 | 16 | extension CompararatorReverseExtensions on Comparator { 17 | /// reverse the sort order of this comparator 18 | Comparator reverse() => 19 | (a, b) => this(b, a); 20 | } 21 | -------------------------------------------------------------------------------- /lib/thirdparty/dartx/int.dart: -------------------------------------------------------------------------------- 1 | extension Ordinals on T { 2 | /// Returns an ordinal number of `String` type for any integer 3 | /// 4 | /// ```dart 5 | /// 101.ordinal(); // 101st 6 | /// 7 | /// 999218.ordinal(); // 999218th 8 | /// ``` 9 | String ordinal() { 10 | final onesPlace = this % 10; 11 | final tensPlace = ((this / 10).floor()) % 10; 12 | if (tensPlace == 1) { 13 | return '${this}th'; 14 | } else { 15 | switch (onesPlace) { 16 | case 1: 17 | return '${this}st'; 18 | case 2: 19 | return '${this}nd'; 20 | case 3: 21 | return '${this}rd'; 22 | default: 23 | return '${this}th'; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/thirdparty/dartx/io/file.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'dart:typed_data'; 4 | 5 | extension FileAppendBytesExtension on File { 6 | /// Appends an array of [bytes] to the content of this file. 7 | Future appendBytes(List bytes) async { 8 | final raf = await open(mode: FileMode.writeOnlyAppend); 9 | await raf.writeFrom(bytes); 10 | await raf.close(); 11 | } 12 | } 13 | 14 | extension FileAppendStringExtension on File { 15 | /// Appends a [string] to the content of this file using UTF-8 or the 16 | /// specified [encoding]. 17 | Future appendString(String string, {Encoding encoding = utf8}) async { 18 | final raf = await open(mode: FileMode.writeOnlyAppend); 19 | await raf.writeString(string); 20 | await raf.close(); 21 | } 22 | } 23 | 24 | extension FileForEachBlockExtension on File { 25 | /// Reads file by byte blocks and calls [action] for each block read. 26 | /// 27 | /// This functions passes the byte buffer to the [action] function. 28 | /// 29 | /// You can use this function for huge files. 30 | Future forEachBlock( 31 | int blockSize, 32 | void Function(Uint8List buffer) action, 33 | ) async { 34 | final raf = await open(); 35 | // ignore: literal_only_boolean_expressions 36 | while (true) { 37 | final buffer = await raf.read(blockSize); 38 | if (buffer.length == blockSize) { 39 | action(buffer); 40 | } else if (buffer.isNotEmpty) { 41 | action(buffer); 42 | break; 43 | } else { 44 | break; 45 | } 46 | } 47 | await raf.close(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/thirdparty/dartx/iterable_num.dart: -------------------------------------------------------------------------------- 1 | /// Extensions for iterables 2 | extension IterableNumSumExtension on Iterable { 3 | /// Returns the sum of all elements in the collection. 4 | T sum() { 5 | num sum = 0.0; 6 | for (final current in this) { 7 | sum += current; 8 | } 9 | if (T == int) { 10 | return sum.toInt() as T; 11 | } else { 12 | return sum.toDouble() as T; 13 | } 14 | } 15 | } 16 | 17 | extension IterableNumAverageExtension on Iterable { 18 | /// Returns the average of all elements in the collection. 19 | double average() { 20 | var count = 0; 21 | num sum = 0; 22 | for (final current in this) { 23 | sum += current; 24 | count++; 25 | } 26 | 27 | if (count == 0) { 28 | throw StateError('No elements in collection'); 29 | } else { 30 | return sum / count; 31 | } 32 | } 33 | } 34 | 35 | extension IterableNumMedianExtension on Iterable { 36 | /// Returns the median of the elements in this collection. 37 | /// 38 | /// Empty collections throw an error. 39 | double median() { 40 | if (length == 0) throw StateError('No elements in collection'); 41 | final values = toList()..sort(); 42 | final size = values.length; 43 | if (size.isOdd) { 44 | return values[(size / 2).floor()].toDouble(); 45 | } else { 46 | final x = values[(size / 2).floor()]; 47 | final y = values[(size / 2).floor() - 1]; 48 | return (x + y) / 2; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/components/generic_context_menu.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | // import 'package:flutter_context_menu/src/widgets/context_menu_state.dart'; 3 | 4 | // import '../core/enums/spawn_direction.dart'; 5 | // import '../core/models/context_menu.dart'; 6 | // import '../widgets/menu_entry_widget.dart'; 7 | 8 | // class GenericContextMenu extends ContextMenu { 9 | // GenericContextMenu({ 10 | // required super.entries, 11 | // super.position, 12 | // super.padding, 13 | // super.borderRadius, 14 | // super.maxWidth, 15 | // super.clipBehavior, 16 | // super.boxDecoration, 17 | // super.shortcuts, 18 | // }); 19 | 20 | // } 21 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/components/menu_divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../core/models/context_menu_entry.dart'; 4 | import '../widgets/context_menu_state.dart'; 5 | import 'menu_header.dart'; 6 | import 'menu_item.dart'; 7 | 8 | /// Represents a divider in a context menu. 9 | /// 10 | /// This class is used to define a divider that can be displayed within a context menu. 11 | /// 12 | /// #### Parameters: 13 | /// - [height] - The height of the divider. 14 | /// - [thickness] - The thickness of the divider. 15 | /// - [indent] - The indent of the divider. 16 | /// - [endIndent] - The end indent of the divider. 17 | /// - [color] - The color of the divider. 18 | /// 19 | /// see: 20 | /// - [ContextMenuEntry] 21 | /// - [MenuHeader] 22 | /// - [MenuItem] 23 | /// 24 | final class MenuDivider extends ContextMenuEntry { 25 | final double? height; 26 | final double? thickness; 27 | final double? indent; 28 | final double? endIndent; 29 | final Color? color; 30 | 31 | const MenuDivider({ 32 | this.height, 33 | this.thickness, 34 | this.indent, 35 | this.endIndent, 36 | this.color, 37 | }) : assert(height == null || height >= 0.0), 38 | assert(thickness == null || thickness >= 0.0), 39 | assert(indent == null || indent >= 0.0), 40 | assert(endIndent == null || endIndent >= 0.0); 41 | 42 | @override 43 | Widget builder(BuildContext context, ContextMenuState menuState) { 44 | return Divider( 45 | height: height ?? 8.0, 46 | thickness: thickness ?? 0.0, 47 | indent: indent, 48 | endIndent: endIndent, 49 | color: color, 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/components/menu_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../core/models/context_menu_entry.dart'; 4 | import '../widgets/context_menu_state.dart'; 5 | import 'menu_divider.dart'; 6 | import 'menu_item.dart'; 7 | 8 | /// Represents a text header in a context menu. 9 | /// 10 | /// This class is used to define a header that can be displayed within a context menu. 11 | /// 12 | /// #### Parameters: 13 | /// - [text] - The text of the header. 14 | /// - [disableUppercase] - Whether to disable the text in uppercase. 15 | /// 16 | /// see: 17 | /// - [ContextMenuEntry] 18 | /// - [MenuDivider] 19 | /// - [MenuItem] 20 | /// 21 | final class MenuHeader extends ContextMenuEntry { 22 | final String text; 23 | final bool disableUppercase; 24 | final double opacity; 25 | 26 | const MenuHeader({ 27 | required this.text, 28 | this.disableUppercase = false, 29 | this.opacity = 0.6, 30 | }); 31 | 32 | @override 33 | Widget builder(BuildContext context, ContextMenuState menuState) { 34 | return Padding( 35 | padding: const EdgeInsets.all(8.0), 36 | child: Align( 37 | alignment: AlignmentDirectional.centerStart, 38 | child: Text( 39 | disableUppercase ? text : text.toUpperCase(), 40 | style: Theme.of(context).textTheme.labelMedium?.copyWith( 41 | color: Theme.of(context).disabledColor.withOpacity(opacity), 42 | ), 43 | ), 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/enums/spawn_direction.dart: -------------------------------------------------------------------------------- 1 | // enum SpawnAlignment { 2 | // topStart, 3 | // topEnd, 4 | // bottomStart, 5 | // bottomEnd, 6 | // } 7 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/models/context_menu_entry.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import '../../widgets/context_menu_state.dart'; 5 | 6 | /// Represents an entry in a context menu. 7 | /// 8 | /// This class is used to define individual items that can be displayed within a context menu. 9 | /// 10 | /// see: 11 | /// - [ContextMenuItem] 12 | /// 13 | abstract base class ContextMenuEntry { 14 | const ContextMenuEntry(); 15 | 16 | /// Builds the widget representation of the context menu entry. 17 | /// 18 | /// - [context] - The context of the widget. 19 | /// - [menuState] - The state of the current context menu. 20 | Widget builder(BuildContext context, ContextMenuState menuState); 21 | 22 | /// Called when the mouse pointer enters the area of the context menu entry. 23 | void onMouseEnter(PointerEnterEvent event, ContextMenuState menuState) {} 24 | 25 | /// Called when the mouse pointer exits the area of the context menu entry. 26 | void onMouseExit(PointerExitEvent event, ContextMenuState menuState) {} 27 | 28 | /// Called when the mouse pointer hovers over the context menu entry. 29 | void onMouseHover(PointerHoverEvent event, ContextMenuState menuState) {} 30 | 31 | String get debugLabel => 32 | '$runtimeType ${hashCode.toString().substring(0, 5)}'; 33 | } 34 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/utils/default_menu_shortcuts.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import '../../widgets/context_menu_state.dart'; 5 | import '../models/context_menu_item.dart'; 6 | 7 | Map defaultMenuShortcuts( 8 | BuildContext context, 9 | ContextMenuItem item, 10 | ContextMenuState menuState, 11 | ) { 12 | return { 13 | const SingleActivator(LogicalKeyboardKey.arrowRight): () { 14 | final bool isSubmenuOpen = menuState.isSubmenuOpen; 15 | final focusedItemIsNotTheSelectedItem = 16 | menuState.focusedEntry != menuState.selectedItem; 17 | if (item.isSubmenuItem && 18 | !isSubmenuOpen && 19 | focusedItemIsNotTheSelectedItem) { 20 | item.handleItemSelection(context); 21 | } 22 | }, 23 | const SingleActivator(LogicalKeyboardKey.arrowLeft): () { 24 | if (menuState.isSubmenu) { 25 | menuState.selfClose?.call(); 26 | } 27 | }, 28 | const SingleActivator(LogicalKeyboardKey.space): () => 29 | item.handleItemSelection(context), 30 | const SingleActivator(LogicalKeyboardKey.enter): () => 31 | item.handleItemSelection(context), 32 | const SingleActivator(LogicalKeyboardKey.numpadEnter): () => 33 | item.handleItemSelection(context), 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/utils/extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | extension BuildContextExtensions on BuildContext { 4 | Rect? getWidgetBounds() { 5 | final widgetRenderBox = findRenderObject() as RenderBox?; 6 | if (widgetRenderBox == null) return null; 7 | final widgetPosition = widgetRenderBox.localToGlobal(Offset.zero); 8 | final widgetSize = widgetRenderBox.size; 9 | return widgetPosition & widgetSize; 10 | } 11 | 12 | ThemeData get theme => Theme.of(this); 13 | ColorScheme get colorScheme => Theme.of(this).colorScheme; 14 | TextTheme get textTheme => Theme.of(this).textTheme; 15 | } 16 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/utils/helpers.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | import '../../widgets/context_menu_state.dart'; 4 | import '../../widgets/context_menu_widget.dart'; 5 | import '../models/context_menu.dart'; 6 | import 'menu_route_options.dart'; 7 | 8 | /// Shows the root context menu popup. 9 | Future showContextMenu( 10 | BuildContext context, { 11 | required ContextMenu contextMenu, 12 | MenuRouteOptions? routeOptions, 13 | }) async { 14 | final menuState = ContextMenuState(menu: contextMenu); 15 | routeOptions ??= const MenuRouteOptions(barrierDismissible: true); 16 | return await Navigator.push( 17 | context, 18 | PageRouteBuilder( 19 | pageBuilder: (context, animation, secondaryAnimation) { 20 | return Stack(children: [ContextMenuWidget(menuState: menuState)]); 21 | }, 22 | fullscreenDialog: true, 23 | settings: routeOptions.routeSettings, 24 | barrierDismissible: routeOptions.barrierDismissible, 25 | opaque: routeOptions.opaque, 26 | transitionDuration: routeOptions.transitionDuration, 27 | reverseTransitionDuration: routeOptions.reverseTransitionDuration, 28 | barrierColor: routeOptions.barrierColor, 29 | barrierLabel: routeOptions.barrierLabel, 30 | transitionsBuilder: routeOptions.transitionsBuilder, 31 | allowSnapshotting: routeOptions.allowSnapshotting, 32 | maintainState: routeOptions.maintainState, 33 | requestFocus: routeOptions.requestFocus, 34 | ), 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/utils/menu_route_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class MenuRouteOptions { 4 | final RouteSettings? routeSettings; 5 | final bool? requestFocus; 6 | final RouteTransitionsBuilder transitionsBuilder; 7 | final Duration transitionDuration; 8 | final Duration reverseTransitionDuration; 9 | final bool opaque; 10 | final bool barrierDismissible; 11 | final Color? barrierColor; 12 | final String? barrierLabel; 13 | final bool maintainState; 14 | final bool allowSnapshotting; 15 | 16 | const MenuRouteOptions({ 17 | this.routeSettings, 18 | this.requestFocus, 19 | this.transitionsBuilder = _defaultTransitionsBuilder, 20 | this.transitionDuration = Duration.zero, 21 | this.reverseTransitionDuration = Duration.zero, 22 | this.opaque = false, 23 | this.barrierDismissible = true, 24 | this.barrierColor, 25 | this.barrierLabel, 26 | this.maintainState = true, 27 | this.allowSnapshotting = true, 28 | }); 29 | } 30 | 31 | Widget _defaultTransitionsBuilder( 32 | context, 33 | animation, 34 | secondaryAnimation, 35 | child, 36 | ) { 37 | return child; 38 | } 39 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/utils/shortcuts/menu_item_shortcuts.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import '../../../widgets/context_menu_state.dart'; 5 | import '../../models/context_menu_item.dart'; 6 | 7 | Map defaultMenuItemShortcuts( 8 | BuildContext context, 9 | ContextMenuItem item, 10 | ContextMenuState menuState, 11 | ) { 12 | final focusedEntry = menuState.focusedEntry; 13 | 14 | return { 15 | // opens submenu of the focused item 16 | const SingleActivator(LogicalKeyboardKey.arrowRight): () { 17 | if (focusedEntry is ContextMenuItem) { 18 | final item = focusedEntry; 19 | 20 | final bool isSubmenuOpen = menuState.isSubmenuOpen; 21 | final focusedItemIsNotTheSelectedItem = 22 | menuState.focusedEntry != menuState.selectedItem; 23 | if (item.isSubmenuItem && 24 | !isSubmenuOpen && 25 | focusedItemIsNotTheSelectedItem) { 26 | item.handleItemSelection(context); 27 | } 28 | } 29 | }, 30 | const SingleActivator(LogicalKeyboardKey.space): () => 31 | item.handleItemSelection(context), 32 | const SingleActivator(LogicalKeyboardKey.enter): () => 33 | item.handleItemSelection(context), 34 | const SingleActivator(LogicalKeyboardKey.numpadEnter): () => 35 | item.handleItemSelection(context), 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/core/utils/shortcuts/menu_shortcuts.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import '../../../widgets/context_menu_state.dart'; 5 | 6 | Map defaultMenuShortcuts( 7 | BuildContext context, 8 | ContextMenuState menuState, 9 | ) { 10 | return { 11 | // closes current submenu 12 | const SingleActivator(LogicalKeyboardKey.arrowLeft): () { 13 | if (menuState.isSubmenu) { 14 | menuState.selfClose?.call(); 15 | } 16 | }, 17 | // navigates to the next item 18 | const SingleActivator(LogicalKeyboardKey.arrowDown): () { 19 | menuState.focusScopeNode.nextFocus(); 20 | }, 21 | // navigates to the previous item 22 | const SingleActivator(LogicalKeyboardKey.arrowUp): () { 23 | menuState.focusScopeNode.previousFocus(); 24 | }, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/flutter_context_menu.dart: -------------------------------------------------------------------------------- 1 | library flutter_context_menu; 2 | 3 | export 'components/menu_divider.dart'; 4 | export 'components/menu_header.dart'; 5 | export 'components/menu_item.dart'; 6 | export 'core/models/context_menu.dart'; 7 | export 'core/models/context_menu_entry.dart'; 8 | export 'core/models/context_menu_item.dart'; 9 | export 'core/utils/helpers.dart'; 10 | export 'widgets/context_menu_region.dart'; 11 | export 'widgets/context_menu_state.dart'; 12 | export 'core/enums/spawn_direction.dart'; 13 | -------------------------------------------------------------------------------- /lib/thirdparty/flutter_context_menu/widgets/context_menu_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | import 'context_menu_state.dart'; 4 | 5 | class ContextMenuProvider extends InheritedNotifier { 6 | const ContextMenuProvider({ 7 | super.key, 8 | required super.child, 9 | required ContextMenuState state, 10 | }) : super(notifier: state); 11 | } 12 | -------------------------------------------------------------------------------- /lib/trios/download_manager/download_request.dart: -------------------------------------------------------------------------------- 1 | class DownloadRequest { 2 | final String url; 3 | final String directory; 4 | final String? filename; 5 | 6 | // var cancelToken = CancelToken(); 7 | var forceDownload = false; 8 | 9 | DownloadRequest(this.url, this.directory, this.filename); 10 | 11 | @override 12 | bool operator ==(Object other) => 13 | identical(this, other) || 14 | other is DownloadRequest && 15 | runtimeType == other.runtimeType && 16 | url == other.url && 17 | directory == other.directory && 18 | filename == other.filename; 19 | 20 | @override 21 | int get hashCode => 22 | url.hashCode ^ directory.hashCode ^ (filename?.hashCode ?? 42); 23 | } 24 | -------------------------------------------------------------------------------- /lib/trios/download_manager/download_status.dart: -------------------------------------------------------------------------------- 1 | enum DownloadStatus { 2 | queued, 3 | retrievingFileInfo, 4 | downloading, 5 | completed, 6 | failed, 7 | paused, 8 | canceled, 9 | } 10 | 11 | extension DownloadStatusExtension on DownloadStatus { 12 | bool get isCompleted { 13 | switch (this) { 14 | case DownloadStatus.queued: 15 | return false; 16 | case DownloadStatus.retrievingFileInfo: 17 | return false; 18 | case DownloadStatus.downloading: 19 | return false; 20 | case DownloadStatus.paused: 21 | return false; 22 | case DownloadStatus.completed: 23 | return true; 24 | case DownloadStatus.failed: 25 | return true; 26 | 27 | case DownloadStatus.canceled: 28 | return true; 29 | } 30 | } 31 | 32 | String get displayString { 33 | switch (this) { 34 | case DownloadStatus.queued: 35 | return "Queued"; 36 | case DownloadStatus.retrievingFileInfo: 37 | return "Retrieving File Info"; 38 | case DownloadStatus.downloading: 39 | return "Downloading"; 40 | case DownloadStatus.completed: 41 | return "Completed"; 42 | case DownloadStatus.failed: 43 | return "Failed"; 44 | case DownloadStatus.paused: 45 | return "Paused"; 46 | case DownloadStatus.canceled: 47 | return "Canceled"; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/trios/download_manager/download_task.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:flutter/foundation.dart'; 5 | 6 | import 'download_request.dart'; 7 | import 'download_status.dart'; 8 | 9 | class DownloadTask { 10 | final DownloadRequest request; 11 | final ValueNotifier status = ValueNotifier( 12 | DownloadStatus.queued, 13 | ); 14 | final ValueNotifier downloaded = ValueNotifier( 15 | DownloadedAmount(0, 0), 16 | ); 17 | final ValueNotifier file = ValueNotifier(null); 18 | Object? error; 19 | 20 | DownloadTask(this.request); 21 | 22 | Future whenDownloadComplete({ 23 | Duration timeout = const Duration(hours: 2), 24 | }) async { 25 | var completer = Completer(); 26 | 27 | if (status.value.isCompleted) { 28 | completer.complete(status.value); 29 | } 30 | 31 | VoidCallback? listener; 32 | listener = () { 33 | if (status.value.isCompleted) { 34 | completer.complete(status.value); 35 | status.removeListener(listener!); 36 | } 37 | }; 38 | 39 | status.addListener(listener); 40 | 41 | return completer.future.timeout(timeout); 42 | } 43 | } 44 | 45 | class DownloadedAmount { 46 | final int bytesReceived; 47 | final int totalBytes; 48 | late double progressRatio = totalBytes == 0 ? 0 : bytesReceived / totalBytes; 49 | 50 | DownloadedAmount(this.bytesReceived, this.totalBytes); 51 | } 52 | -------------------------------------------------------------------------------- /lib/trios/navigation.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | 3 | part 'navigation.mapper.dart'; 4 | 5 | @MappableEnum(defaultValue: TriOSTools.dashboard) 6 | enum TriOSTools { 7 | dashboard, 8 | modManager, 9 | modProfiles, 10 | vramEstimator, 11 | chipper, 12 | jreManager, 13 | portraits, 14 | weapons, 15 | ships, 16 | settings, 17 | catalog, 18 | tips, 19 | } 20 | -------------------------------------------------------------------------------- /lib/trios/providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 2 | import 'package:trios/trios/settings/app_settings_logic.dart'; 3 | import 'package:trios/trios/settings/settings.dart'; 4 | import 'package:trios/utils/http_client.dart'; 5 | 6 | final triOSHttpClient = Provider( 7 | (ref) => TriOSHttpClient( 8 | config: ApiClientConfig(), 9 | maxConcurrentRequests: ref.watch( 10 | appSettings.select((s) => s.maxHttpRequestsAtOnce), 11 | ), 12 | ), 13 | ); 14 | -------------------------------------------------------------------------------- /lib/utils/relative_timestamp.dart: -------------------------------------------------------------------------------- 1 | extension RelativeTimeExtension on DateTime { 2 | String relativeTimestamp() { 3 | final Duration difference = DateTime.now().difference(this); 4 | final bool isPast = difference.isNegative == false; 5 | final int seconds = difference.inSeconds.abs(); 6 | final int minutes = difference.inMinutes.abs(); 7 | final int hours = difference.inHours.abs(); 8 | final int days = difference.inDays.abs(); 9 | 10 | String timeString; 11 | String unit; 12 | 13 | if (seconds < 60) { 14 | unit = seconds == 1 ? 'second' : 'seconds'; 15 | timeString = '$seconds $unit'; 16 | } else if (minutes < 60) { 17 | unit = minutes == 1 ? 'minute' : 'minutes'; 18 | timeString = '$minutes $unit'; 19 | } else if (hours < 24) { 20 | unit = hours == 1 ? 'hour' : 'hours'; 21 | timeString = '$hours $unit'; 22 | } else if (days < 7) { 23 | unit = days == 1 ? 'day' : 'days'; 24 | timeString = '$days $unit'; 25 | } else if (days < 30) { 26 | final weeks = (days / 7).floor(); 27 | unit = weeks == 1 ? 'week' : 'weeks'; 28 | timeString = '$weeks $unit'; 29 | } else if (days < 365) { 30 | final months = (days / 30).floor(); 31 | unit = months == 1 ? 'month' : 'months'; 32 | timeString = '$months $unit'; 33 | } else { 34 | final years = (days / 365).floor(); 35 | unit = years == 1 ? 'year' : 'years'; 36 | timeString = '$years $unit'; 37 | } 38 | 39 | return isPast ? '$timeString ago' : 'in $timeString'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/vram_estimator/image_reader/image_reader_async.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:image/image.dart' as img; 4 | 5 | import 'png_chatgpt.dart'; 6 | 7 | class ReadImageHeaders { 8 | Future readPng(String path) async { 9 | return readPngFileHeaders(path); 10 | } 11 | 12 | Future readGeneric(String path) async { 13 | final file = File(path); 14 | 15 | if (img.findDecoderForNamedImage(file.path) == null) { 16 | throw Exception("Not an image."); 17 | } 18 | 19 | final image = 20 | (await (img.Command() 21 | ..decodeNamedImage(file.path, file.readAsBytesSync())) 22 | .executeThread()) 23 | .outputImage; 24 | 25 | if (image == null) { 26 | throw Exception("Failed to read image."); 27 | } 28 | 29 | return ImageHeader( 30 | image.width, 31 | image.height, 32 | image.bitsPerChannel, 33 | image.numChannels, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/vram_estimator/models/gpu_info.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_extensions_methods/dart_extension_methods.dart'; 4 | import 'package:trios/utils/logging.dart'; 5 | import 'package:trios/utils/extensions.dart'; 6 | import 'package:windows_system_info/windows_system_info.dart'; 7 | 8 | abstract class GPUInfo { 9 | abstract double freeVRAM; 10 | abstract List? gpuString; 11 | } 12 | 13 | GPUInfo? getGPUInfo() { 14 | if (Platform.isWindows) { 15 | var gpu = WindowsSystemInfo.graphics?.controllers.maxByOrNull( 16 | (controller) => controller.vram, 17 | ); 18 | if (gpu != null) { 19 | return WindowsGPUInfo(gpu); 20 | } 21 | } else if (Platform.isMacOS) { 22 | try { 23 | return MacOSGPUInfo(); 24 | } catch (e) { 25 | Fimber.w(e.toString()); 26 | return null; 27 | } 28 | } 29 | 30 | return null; 31 | } 32 | 33 | class WindowsGPUInfo implements GPUInfo { 34 | @override 35 | late double freeVRAM; 36 | @override 37 | late List? gpuString; 38 | Controller controller; 39 | 40 | WindowsGPUInfo(this.controller) { 41 | freeVRAM = controller.vram; 42 | gpuString = [controller.model]; 43 | } 44 | 45 | @override 46 | String toString() { 47 | return "GPUInfo(freeVRAM: $freeVRAM, gpuString: $gpuString)"; 48 | } 49 | } 50 | 51 | class MacOSGPUInfo implements GPUInfo { 52 | @override 53 | late double freeVRAM; 54 | 55 | @override 56 | late List? gpuString; 57 | 58 | MacOSGPUInfo() { 59 | const memoryCmd = "sysctl"; 60 | 61 | final process = Process.runSync(memoryCmd, ['-a'], runInShell: true); 62 | var result = process.stdout.toString(); 63 | if (process.exitCode != 0) { 64 | throw Exception( 65 | "'$memoryCmd' failed with code ${process.exitCode}\n${process.stderr}", 66 | ); 67 | } 68 | 69 | result = result 70 | .split("\n") 71 | .firstWhere((it) => it.containsIgnoreCase("hw.memsize_usable")); 72 | 73 | gpuString = []; 74 | freeVRAM = result.split(":")[1].trim().toDouble(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/vram_estimator/models/graphics_lib_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | import 'package:trios/vram_estimator/models/graphics_lib_lunaconfig.dart'; 3 | 4 | part 'graphics_lib_config.mapper.dart'; 5 | 6 | @MappableClass() 7 | class GraphicsLibConfig with GraphicsLibConfigMappable { 8 | @MappableField(key: 'enableShaders') 9 | final bool areAnyEffectsEnabled; 10 | 11 | @MappableField(key: 'enableNormal') 12 | final bool areGfxLibNormalMapsEnabled; 13 | 14 | @MappableField(key: 'loadMaterial') 15 | final bool areGfxLibMaterialMapsEnabled; 16 | 17 | @MappableField(key: 'loadSurface') 18 | final bool areGfxLibSurfaceMapsEnabled; 19 | 20 | @MappableField(key: 'autoGenNormals') 21 | final bool autoGenNormals; 22 | 23 | @MappableField(key: 'preloadAllMaps') 24 | final bool preloadAllMaps; 25 | 26 | const GraphicsLibConfig({ 27 | required this.areAnyEffectsEnabled, 28 | required this.areGfxLibNormalMapsEnabled, 29 | required this.areGfxLibMaterialMapsEnabled, 30 | required this.areGfxLibSurfaceMapsEnabled, 31 | required this.autoGenNormals, 32 | required this.preloadAllMaps, 33 | }); 34 | 35 | static const disabled = GraphicsLibConfig( 36 | areAnyEffectsEnabled: false, 37 | areGfxLibNormalMapsEnabled: false, 38 | areGfxLibMaterialMapsEnabled: false, 39 | areGfxLibSurfaceMapsEnabled: false, 40 | autoGenNormals: false, 41 | preloadAllMaps: false, 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /lib/vram_estimator/models/graphics_lib_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | 3 | part 'graphics_lib_info.mapper.dart'; 4 | 5 | @MappableClass() 6 | class GraphicsLibInfo with GraphicsLibInfoMappable { 7 | String id; 8 | MapType mapType; 9 | String relativeFilePath; 10 | 11 | GraphicsLibInfo(this.id, this.mapType, this.relativeFilePath); 12 | 13 | @override 14 | String toString() { 15 | return "GraphicsLibInfo(id: $id,mapType: $mapType, relativeFilePath: $relativeFilePath)"; 16 | } 17 | } 18 | 19 | @MappableEnum() 20 | enum MapType { Normal, Material, Surface } 21 | -------------------------------------------------------------------------------- /lib/vram_estimator/models/graphics_lib_lunaconfig.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mappable/dart_mappable.dart'; 2 | import 'package:trios/vram_estimator/models/graphics_lib_config.dart'; 3 | 4 | part 'graphics_lib_lunaconfig.mapper.dart'; 5 | 6 | @MappableClass() 7 | class GraphicsLibLunaConfig with GraphicsLibLunaConfigMappable { 8 | final bool aaCompatMode; 9 | final bool autoGenNormals; 10 | final bool enableNormal; 11 | final bool enableShaders; 12 | final bool loadMaterial; 13 | final bool loadSurface; 14 | final bool optimizeNormals; 15 | final bool preloadAllMaps; 16 | 17 | const GraphicsLibLunaConfig({ 18 | this.aaCompatMode = false, 19 | this.autoGenNormals = true, 20 | this.enableNormal = true, 21 | this.enableShaders = true, 22 | this.loadMaterial = true, 23 | this.loadSurface = true, 24 | this.optimizeNormals = false, 25 | this.preloadAllMaps = false, 26 | }); 27 | 28 | GraphicsLibConfig toGraphicsLibConfig() { 29 | return GraphicsLibConfig( 30 | areAnyEffectsEnabled: enableShaders, 31 | areGfxLibNormalMapsEnabled: enableNormal, 32 | areGfxLibMaterialMapsEnabled: loadMaterial, 33 | areGfxLibSurfaceMapsEnabled: loadSurface, 34 | autoGenNormals: autoGenNormals, 35 | preloadAllMaps: preloadAllMaps, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/widgets/MultiSplitViewMixin.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:multi_split_view/multi_split_view.dart'; 3 | 4 | mixin MultiSplitViewMixin on State { 5 | late MultiSplitViewController multiSplitController = MultiSplitViewController( 6 | areas: areas, 7 | ); 8 | 9 | List get areas; 10 | 11 | @override 12 | void initState() { 13 | super.initState(); 14 | multiSplitController.addListener(onMultiSplitViewChanged); 15 | } 16 | 17 | @override 18 | void dispose() { 19 | multiSplitController.removeListener(onMultiSplitViewChanged); 20 | super.dispose(); 21 | } 22 | 23 | /// Called when the MultiSplitView changes 24 | void onMultiSplitViewChanged() { 25 | setState(() { 26 | // Rebuild to update the UI when the controller changes 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/widgets/blur.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class Blur extends StatelessWidget { 6 | const Blur({ 7 | super.key, 8 | required this.child, 9 | this.blurX, 10 | this.blurY, 11 | this.blur = 5, 12 | this.blurColor = Colors.white, 13 | this.blurOpacity = 1.0, 14 | this.colorOpacity = 0.0, 15 | this.alignment, 16 | }) : assert((blurX != null && blurY != null) || blur != null); 17 | 18 | final Widget child; 19 | final double? blurX; 20 | final double? blurY; 21 | final double? blur; 22 | final Color blurColor; 23 | final double blurOpacity; 24 | final double colorOpacity; 25 | final AlignmentGeometry? alignment; 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Stack( 30 | children: [ 31 | Opacity( 32 | opacity: blurOpacity, 33 | child: ImageFiltered( 34 | imageFilter: ImageFilter.blur( 35 | sigmaX: blurX ?? blur!, 36 | sigmaY: blurY ?? blur!, 37 | ), 38 | child: Container( 39 | decoration: BoxDecoration( 40 | color: blurColor.withOpacity(colorOpacity), 41 | ), 42 | alignment: alignment, 43 | child: child, 44 | ), 45 | ), 46 | ), 47 | child, 48 | ], 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/widgets/centered_widget_with_item_after.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CenteredWidgetWithItemAfter extends StatelessWidget { 4 | final Widget centeredWidget; 5 | final Widget itemAfter; 6 | 7 | const CenteredWidgetWithItemAfter({ 8 | super.key, 9 | required this.centeredWidget, 10 | required this.itemAfter, 11 | }); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | final LayerLink layerLink = LayerLink(); 16 | 17 | return Stack( 18 | children: [ 19 | Align( 20 | child: CompositedTransformTarget( 21 | link: layerLink, 22 | child: centeredWidget, 23 | ), 24 | ), 25 | CompositedTransformFollower( 26 | link: layerLink, 27 | targetAnchor: Alignment.centerRight, 28 | followerAnchor: Alignment.centerLeft, 29 | child: itemAfter, 30 | ), 31 | ], 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/widgets/conditional_wrap.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class ConditionalWrap extends StatelessWidget { 4 | /// Creates a widget that conditionally wraps its [child]. 5 | const ConditionalWrap({ 6 | super.key, 7 | required this.condition, 8 | required this.wrapper, 9 | this.fallback, 10 | required this.child, 11 | }); 12 | 13 | /// Decides on which [Wrapper] to use. 14 | final bool condition; 15 | 16 | /// Wrapper to use when [condition] is true. 17 | final Widget Function(Widget child) wrapper; 18 | 19 | /// Wrapper to use when [condition] is false. 20 | /// 21 | /// If not specified, [child] is returned. 22 | final Widget Function(Widget child)? fallback; 23 | 24 | /// Widget to be conditionally wrapped. 25 | final Widget child; 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | if (condition) { 30 | return wrapper(child); 31 | } else if (fallback != null) { 32 | return fallback!(child); 33 | } else { 34 | return child; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/widgets/dense_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | enum DenseButtonStyle { compact, extraCompact } 4 | 5 | class DenseButton extends StatelessWidget { 6 | final Widget child; 7 | final DenseButtonStyle density; 8 | 9 | const DenseButton({ 10 | super.key, 11 | required this.child, 12 | this.density = DenseButtonStyle.compact, 13 | }); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | final EdgeInsetsGeometry padding = density == DenseButtonStyle.extraCompact 18 | ? const EdgeInsets.symmetric(horizontal: 6, vertical: 2) 19 | : const EdgeInsets.symmetric(horizontal: 10, vertical: 6); 20 | 21 | final Size minimumSize = density == DenseButtonStyle.extraCompact 22 | ? const Size(0, 24) 23 | : const Size(0, 30); 24 | 25 | return Theme( 26 | data: Theme.of(context).copyWith( 27 | textButtonTheme: TextButtonThemeData( 28 | style: TextButton.styleFrom( 29 | padding: padding, 30 | minimumSize: minimumSize, 31 | tapTargetSize: MaterialTapTargetSize.shrinkWrap, 32 | ), 33 | ), 34 | outlinedButtonTheme: OutlinedButtonThemeData( 35 | style: OutlinedButton.styleFrom( 36 | padding: padding, 37 | minimumSize: minimumSize, 38 | tapTargetSize: MaterialTapTargetSize.shrinkWrap, 39 | ), 40 | ), 41 | elevatedButtonTheme: ElevatedButtonThemeData( 42 | style: ElevatedButton.styleFrom( 43 | padding: padding, 44 | minimumSize: minimumSize, 45 | tapTargetSize: MaterialTapTargetSize.shrinkWrap, 46 | ), 47 | ), 48 | ), 49 | child: child, 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/widgets/disable.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Disable extends StatelessWidget { 4 | final Widget child; 5 | final bool isEnabled; 6 | 7 | const Disable({super.key, required this.child, required this.isEnabled}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return AbsorbPointer( 12 | absorbing: !isEnabled, // Disables interaction 13 | child: AnimatedSwitcher( 14 | duration: const Duration(milliseconds: 200), 15 | child: Opacity( 16 | opacity: isEnabled ? 1.0 : 0.5, // Grays out when disabled 17 | child: child, 18 | ), 19 | ), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/widgets/disable_if_cannot_write_game_folder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:trios/trios/constants.dart'; 4 | import 'package:trios/widgets/conditional_wrap.dart'; 5 | import 'package:trios/widgets/disable.dart'; 6 | 7 | import '../trios/app_state.dart'; 8 | 9 | class DisableIfCannotWriteGameFolder extends ConsumerStatefulWidget { 10 | final Widget child; 11 | 12 | const DisableIfCannotWriteGameFolder({super.key, required this.child}); 13 | 14 | @override 15 | ConsumerState createState() => _DisableIfCannotWriteGameFolderState(); 16 | } 17 | 18 | class _DisableIfCannotWriteGameFolderState 19 | extends ConsumerState { 20 | @override 21 | Widget build(BuildContext context) { 22 | final canWrite = ref.watch(AppState.canWriteToModsFolder).value ?? true; 23 | return ConditionalWrap( 24 | condition: !canWrite, 25 | wrapper: (child) => Tooltip( 26 | message: 27 | "Cannot modify game folder and/or vmparams.\nTry running ${Constants.appName} as administrator.", 28 | child: Disable(isEnabled: false, child: child), 29 | ), 30 | child: widget.child, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/widgets/disable_if_cannot_write_mods.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:trios/trios/constants.dart'; 4 | import 'package:trios/widgets/conditional_wrap.dart'; 5 | import 'package:trios/widgets/disable.dart'; 6 | 7 | import '../trios/app_state.dart'; 8 | 9 | class DisableIfCannotWriteMods extends ConsumerStatefulWidget { 10 | final Widget child; 11 | 12 | const DisableIfCannotWriteMods({super.key, required this.child}); 13 | 14 | @override 15 | ConsumerState createState() => _DisableIfCannotWriteModsState(); 16 | } 17 | 18 | class _DisableIfCannotWriteModsState 19 | extends ConsumerState { 20 | @override 21 | Widget build(BuildContext context) { 22 | final canWriteMods = ref.watch(AppState.canWriteToModsFolder).value ?? true; 23 | 24 | return ConditionalWrap( 25 | condition: !canWriteMods, 26 | wrapper: (child) => Tooltip( 27 | message: 28 | "Cannot modify mods folder.\nTry running ${Constants.appName} as administrator and make sure that mods/enabled_mods.json exists and can be modified.", 29 | child: Disable(isEnabled: false, child: child), 30 | ), 31 | child: widget.child, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/widgets/download_progress_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:trios/models/download_progress.dart'; 4 | import 'package:trios/utils/extensions.dart'; 5 | 6 | class TriOSDownloadProgressIndicator extends ConsumerStatefulWidget { 7 | final TriOSDownloadProgress value; 8 | final Color? color; 9 | 10 | const TriOSDownloadProgressIndicator({ 11 | super.key, 12 | required this.value, 13 | this.color, 14 | }); 15 | 16 | @override 17 | ConsumerState createState() => _TriOSDownloadProgressIndicatorState(); 18 | } 19 | 20 | class _TriOSDownloadProgressIndicatorState 21 | extends ConsumerState { 22 | @override 23 | Widget build(BuildContext context) { 24 | return Column( 25 | children: [ 26 | ClipRRect( 27 | borderRadius: BorderRadius.circular(3), 28 | child: LinearProgressIndicator( 29 | value: widget.value.isIndeterminate 30 | ? null 31 | : widget.value.progressPercent, 32 | minHeight: 10, 33 | color: widget.color, 34 | ), 35 | ), 36 | Text( 37 | widget.value.bytesReceived == 0 && widget.value.bytesTotal == 0 38 | ? "" 39 | : widget.value.bytesReceived == widget.value.bytesTotal 40 | ? widget.value.bytesTotal.bytesAsReadableMB() 41 | : "${widget.value.bytesReceived.bytesAsReadableMB()} / ${widget.value.bytesTotal.bytesAsReadableMB()}", 42 | style: Theme.of(context).textTheme.labelSmall, 43 | ), 44 | ], 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/widgets/fancy_mod_tooltip_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:trios/widgets/palette_generator_mixin.dart'; 3 | 4 | import '../themes/theme_manager.dart'; 5 | 6 | class ModTooltipFancyTitleHeader extends StatefulWidget { 7 | const ModTooltipFancyTitleHeader({ 8 | super.key, 9 | required this.iconPath, 10 | required this.child, 11 | }); 12 | 13 | final String? iconPath; 14 | final Widget child; 15 | 16 | @override 17 | State createState() => 18 | _ModTooltipFancyTitleHeaderState(); 19 | } 20 | 21 | class _ModTooltipFancyTitleHeaderState extends State 22 | with PaletteGeneratorMixin { 23 | @override 24 | String? getIconPath() => widget.iconPath; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | final paletteTheme = paletteGenerator.createPaletteTheme(context); 29 | 30 | return Theme( 31 | data: paletteTheme, 32 | child: Container( 33 | padding: const EdgeInsets.only(top: 4, bottom: 4), 34 | decoration: BoxDecoration( 35 | color: paletteGenerator != null 36 | ? paletteTheme.colorScheme.surface 37 | : paletteTheme.colorScheme.surfaceContainerLow, 38 | borderRadius: const BorderRadius.only( 39 | topLeft: Radius.circular(ThemeManager.cornerRadius), 40 | topRight: Radius.circular(ThemeManager.cornerRadius), 41 | ), 42 | border: Border( 43 | top: BorderSide( 44 | color: paletteTheme.colorScheme.onSurface.withOpacity(0.15), 45 | width: 1, 46 | ), 47 | left: BorderSide( 48 | color: paletteTheme.colorScheme.onSurface.withOpacity(0.15), 49 | width: 1, 50 | ), 51 | bottom: BorderSide( 52 | color: paletteTheme.colorScheme.onSurface.withOpacity(0.15), 53 | width: 1, 54 | ), 55 | ), 56 | ), 57 | child: widget.child, 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/widgets/mod_type_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:trios/models/mod_variant.dart'; 3 | import 'package:trios/widgets/moving_tooltip.dart'; 4 | import 'package:trios/widgets/svg_image_icon.dart'; 5 | 6 | class ModTypeIcon extends StatelessWidget { 7 | const ModTypeIcon({super.key, required this.modVariant}); 8 | 9 | final ModVariant modVariant; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return modVariant.modInfo.isTotalConversion || modVariant.modInfo.isUtility 14 | ? MovingTooltipWidget.text( 15 | message: getTooltipText(modVariant), 16 | child: Opacity( 17 | opacity: 0.7, 18 | child: SizedBox( 19 | width: 24, 20 | height: 24, 21 | child: modVariant.modInfo.isTotalConversion 22 | ? const SvgImageIcon("assets/images/icon-death-star.svg") 23 | : modVariant.modInfo.isUtility 24 | ? const SvgImageIcon("assets/images/icon-utility-mod.svg") 25 | : Container(), 26 | ), 27 | ), 28 | ) 29 | : Container(); 30 | } 31 | 32 | static getTooltipText(ModVariant modVariant) { 33 | return modVariant.modInfo.isTotalConversion 34 | ? "Total Conversion mods should not be run with any other mods, except Utility mods, unless explicitly stated to be compatible." 35 | : modVariant.modInfo.isUtility 36 | ? "Utility mods may be added to or removed from a save at will." 37 | : ""; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/widgets/palette_generator_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:palette_generator/palette_generator.dart'; 3 | import 'package:trios/utils/extensions.dart'; 4 | import 'package:trios/utils/logging.dart'; 5 | 6 | mixin PaletteGeneratorMixin on State { 7 | PaletteGenerator? paletteGenerator; 8 | 9 | // Shhh 10 | // Will not update if mod changes the icon during runtime. 11 | static final Map _cachedThemes = {}; 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | _generatePalette(); 17 | } 18 | 19 | @override 20 | void didUpdateWidget(covariant T oldWidget) { 21 | super.didUpdateWidget(oldWidget); 22 | _generatePalette(); 23 | } 24 | 25 | Future _generatePalette() async { 26 | final iconPath = getIconPath(); 27 | 28 | if (_cachedThemes.containsKey(iconPath)) { 29 | paletteGenerator = _cachedThemes[iconPath]; 30 | } else if (iconPath?.isNotEmpty == true) { 31 | final icon = Image.file(iconPath!.toFile()); 32 | paletteGenerator = await PaletteGenerator.fromImageProvider(icon.image); 33 | Fimber.v(() => "Generated palette for $iconPath"); 34 | _cachedThemes[iconPath] = paletteGenerator; 35 | } else { 36 | paletteGenerator = null; 37 | } 38 | 39 | if (!mounted) return; 40 | 41 | setState(() {}); 42 | } 43 | 44 | String? getIconPath(); 45 | } 46 | -------------------------------------------------------------------------------- /lib/widgets/restartable_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RestartableApp extends StatefulWidget { 4 | final Widget child; 5 | 6 | const RestartableApp({super.key, required this.child}); 7 | 8 | static void restartApp(BuildContext context) { 9 | context.findAncestorStateOfType<_RestartableAppState>()?.restartApp(); 10 | } 11 | 12 | @override 13 | State createState() => _RestartableAppState(); 14 | } 15 | 16 | class _RestartableAppState extends State { 17 | Key key = UniqueKey(); 18 | 19 | void restartApp() { 20 | setState(() { 21 | key = UniqueKey(); 22 | }); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return KeyedSubtree(key: key, child: widget.child); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/widgets/settings_group.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SettingsGroup extends StatelessWidget { 4 | final String name; 5 | final List children; 6 | final double padding; 7 | 8 | const SettingsGroup({ 9 | super.key, 10 | required this.name, 11 | required this.children, 12 | this.padding = 16, 13 | }); 14 | 15 | static SettingsGroup subsection({ 16 | required String name, 17 | required List children, 18 | }) => SettingsGroup(name: name, padding: 4, children: children); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | final theme = Theme.of(context); 23 | 24 | return Padding( 25 | padding: const EdgeInsets.only(left: 8, top: 16, bottom: 16), 26 | child: Column( 27 | crossAxisAlignment: CrossAxisAlignment.start, 28 | children: [ 29 | Row( 30 | children: [ 31 | Text( 32 | name, 33 | style: Theme.of(context).textTheme.labelLarge?.copyWith(), 34 | ), 35 | Expanded( 36 | child: Divider( 37 | indent: 8, 38 | color: theme.colorScheme.onSurface.withOpacity(0.15), 39 | ), 40 | ), 41 | ], 42 | ), 43 | SizedBox(height: padding), 44 | Padding( 45 | padding: const EdgeInsets.only(left: 24), 46 | child: Column( 47 | crossAxisAlignment: CrossAxisAlignment.start, 48 | children: children, 49 | ), 50 | ), 51 | ], 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/widgets/simple_data_row.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SimpleDataRow extends StatelessWidget { 4 | final String label; 5 | final String value; 6 | 7 | const SimpleDataRow({super.key, required this.label, required this.value}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return RichText( 12 | text: TextSpan( 13 | style: Theme.of(context).textTheme.labelLarge, 14 | children: [ 15 | TextSpan( 16 | text: label, 17 | style: const TextStyle(fontWeight: FontWeight.w100), 18 | ), 19 | TextSpan( 20 | text: value, 21 | style: Theme.of( 22 | context, 23 | ).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.bold), 24 | ), 25 | ], 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/widgets/svg_image_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | 4 | class SvgImageIcon extends StatelessWidget { 5 | final String assetName; 6 | final double? width; 7 | final double? height; 8 | final Color? color; 9 | 10 | const SvgImageIcon( 11 | this.assetName, { 12 | super.key, 13 | this.width, 14 | this.height, 15 | this.color, 16 | }); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | final iconThemeData = IconTheme.of(context); 21 | final colorLocal = color ?? iconThemeData.color; 22 | return Opacity( 23 | opacity: iconThemeData.opacity ?? 1, 24 | child: SvgPicture.asset( 25 | assetName, 26 | width: width, 27 | height: height, 28 | fit: BoxFit.scaleDown, 29 | colorFilter: colorLocal == null 30 | ? null 31 | : ColorFilter.mode(colorLocal, BlendMode.srcIn), 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/widgets/tab_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TabButton extends StatelessWidget { 4 | final String text; 5 | final bool isSelected; 6 | final VoidCallback onPressed; 7 | final Widget icon; 8 | final double iconSize; 9 | final double iconSpacing; 10 | 11 | const TabButton({ 12 | super.key, 13 | required this.text, 14 | required this.isSelected, 15 | required this.onPressed, 16 | required this.icon, 17 | this.iconSize = 24, 18 | this.iconSpacing = 2, 19 | }); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | final colors = Theme.of(context).colorScheme; 24 | final foregroundColor = isSelected 25 | ? colors.primary 26 | : colors.onSurface.withOpacity(0.8); 27 | 28 | return Padding( 29 | padding: const EdgeInsets.all(0), 30 | child: TextButton( 31 | style: TextButton.styleFrom( 32 | padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), 33 | backgroundColor: isSelected ? Colors.transparent : Colors.transparent, 34 | foregroundColor: foregroundColor, 35 | shape: RoundedRectangleBorder( 36 | borderRadius: BorderRadius.circular(0.0), 37 | ), 38 | ), 39 | onPressed: onPressed, 40 | child: Column( 41 | mainAxisSize: MainAxisSize.min, 42 | mainAxisAlignment: MainAxisAlignment.center, 43 | children: [ 44 | IconTheme( 45 | data: IconThemeData(color: foregroundColor), 46 | child: SizedBox(height: iconSize, child: icon), 47 | ), 48 | SizedBox(height: iconSpacing), 49 | Text( 50 | text, 51 | style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500), 52 | ), 53 | ], 54 | ), 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/widgets/text_trios.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:trios/widgets/moving_tooltip.dart'; 3 | 4 | /// Shows a tooltip if the text is too long to fit in the available space. 5 | class TextTriOS extends StatelessWidget { 6 | final String text; 7 | final TextStyle? style; 8 | final TextAlign? textAlign; 9 | final int? maxLines; 10 | final TextOverflow overflow; 11 | 12 | const TextTriOS( 13 | this.text, { 14 | super.key, 15 | this.style, 16 | this.textAlign, 17 | this.maxLines, 18 | this.overflow = TextOverflow.ellipsis, 19 | }); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | final textWidget = Text( 24 | text, 25 | style: style, 26 | textAlign: textAlign, 27 | overflow: overflow, 28 | maxLines: maxLines, 29 | ); 30 | 31 | return LayoutBuilder( 32 | builder: (context, constraints) { 33 | final textPainter = TextPainter( 34 | text: TextSpan( 35 | text: text, 36 | style: style ?? DefaultTextStyle.of(context).style, 37 | ), 38 | maxLines: maxLines, 39 | textDirection: Directionality.of(context), 40 | )..layout(maxWidth: constraints.maxWidth); 41 | 42 | final isOverflowing = textPainter.didExceedMaxLines; 43 | 44 | return isOverflowing 45 | ? MovingTooltipWidget.text(message: text, child: textWidget) 46 | : textWidget; 47 | }, 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/widgets/text_with_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TextWithIcon extends StatelessWidget { 4 | final String? text; 5 | final Widget? widget; 6 | final Widget? leading; 7 | final Widget? trailing; 8 | final TextStyle? style; 9 | final TextOverflow? overflow; 10 | final int? maxLines; 11 | final EdgeInsetsGeometry? leadingPadding; 12 | final EdgeInsetsGeometry? trailingPadding; 13 | 14 | const TextWithIcon({ 15 | super.key, 16 | this.text, 17 | this.widget, 18 | this.leading, 19 | this.trailing, 20 | this.style, 21 | this.overflow, 22 | this.maxLines, 23 | this.leadingPadding = const EdgeInsets.only(right: 8.0), 24 | this.trailingPadding = const EdgeInsets.only(left: 8.0), 25 | }) : assert(text != null || widget != null); 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Row( 30 | mainAxisSize: MainAxisSize.min, 31 | children: [ 32 | if (leading != null) Padding(padding: leadingPadding!, child: leading), 33 | Flexible( 34 | child: text != null 35 | ? Text( 36 | text!, 37 | style: style, 38 | overflow: overflow, 39 | maxLines: maxLines, 40 | ) 41 | : widget!, 42 | ), 43 | if (trailing != null) 44 | Padding(padding: trailingPadding!, child: trailing), 45 | ], 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/widgets/toolbar_checkbox_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:trios/widgets/checkbox_with_label.dart'; 3 | 4 | class TriOSToolbarCheckboxButton extends StatelessWidget { 5 | const TriOSToolbarCheckboxButton({ 6 | super.key, 7 | required this.text, 8 | required this.value, 9 | required this.onChanged, 10 | }); 11 | 12 | final String text; 13 | final bool value; 14 | final ValueChanged onChanged; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | final theme = Theme.of(context); 19 | return TriOSToolbarItem( 20 | child: CheckboxWithLabel( 21 | labelWidget: Padding( 22 | padding: const EdgeInsets.only(right: 4), 23 | child: Text( 24 | text, 25 | style: theme.textTheme.labelLarge!.copyWith(fontSize: 14), 26 | ), 27 | ), 28 | textPadding: const EdgeInsets.only(left: 4), 29 | checkWrapper: (child) => 30 | Padding(padding: const EdgeInsets.only(left: 4), child: child), 31 | value: value, 32 | onChanged: onChanged, 33 | ), 34 | ); 35 | } 36 | } 37 | 38 | class TriOSToolbarItem extends StatelessWidget { 39 | const TriOSToolbarItem({super.key, required this.child}); 40 | 41 | final Widget child; 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | final theme = Theme.of(context); 46 | return SizedBox( 47 | height: 30, 48 | child: Card.outlined( 49 | margin: const EdgeInsets.symmetric(), 50 | child: DefaultTextStyle.merge( 51 | child: child, 52 | style: theme.textTheme.labelLarge?.copyWith( 53 | color: theme.colorScheme.onSurface, 54 | ), 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/widgets/tooltip_frame.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../themes/theme_manager.dart'; 4 | 5 | class TooltipFrame extends StatelessWidget { 6 | final Widget child; 7 | final EdgeInsetsGeometry padding; 8 | final Color? backgroundColor; 9 | final Color? borderColor; 10 | 11 | const TooltipFrame({ 12 | super.key, 13 | required this.child, 14 | this.padding = const EdgeInsets.all(8), 15 | this.backgroundColor, 16 | this.borderColor, 17 | }); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | final theme = Theme.of(context); 22 | return Card( 23 | child: Container( 24 | decoration: BoxDecoration( 25 | color: backgroundColor ?? theme.cardColor, 26 | borderRadius: BorderRadius.circular(ThemeManager.cornerRadius), 27 | border: Border.all(color: borderColor ?? theme.colorScheme.secondary), 28 | boxShadow: [ 29 | BoxShadow( 30 | color: Colors.black.withOpacity(0.4), 31 | // Adjust shadow color and opacity as needed 32 | blurRadius: 10, 33 | // Adjust blur radius for the shadow effect 34 | offset: const Offset( 35 | 0, 36 | 4, 37 | ), // Adjust offset for the shadow position 38 | ), 39 | ], 40 | ), 41 | child: Padding(padding: padding, child: child), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/widgets/trios_app_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | 4 | class TriOSAppIcon extends StatelessWidget { 5 | final double width; 6 | final double height; 7 | 8 | const TriOSAppIcon({super.key, this.width = 48, this.height = 48}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return SvgPicture.asset( 13 | ("assets/images/telos_faction_crest.svg"), 14 | colorFilter: ColorFilter.mode( 15 | Theme.of(context).colorScheme.primary, 16 | BlendMode.srcIn, 17 | ), 18 | width: width, 19 | height: height, 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/widgets/tristate_icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TristateIconButton extends StatefulWidget { 4 | final bool? value; 5 | final ValueChanged onChanged; 6 | final Widget trueIcon; 7 | final Widget? falseIcon; 8 | final Widget? nullIcon; 9 | 10 | const TristateIconButton({ 11 | super.key, 12 | required this.value, 13 | required this.onChanged, 14 | required this.trueIcon, 15 | this.falseIcon, 16 | this.nullIcon, 17 | }); 18 | 19 | @override 20 | State createState() => _TristateIconButtonState(); 21 | } 22 | 23 | class _TristateIconButtonState extends State { 24 | bool? _currentState; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | _currentState = widget.value; 30 | } 31 | 32 | void _toggleState() { 33 | setState(() { 34 | _currentState = switch (_currentState) { 35 | true => false, 36 | false => null, 37 | null => true, 38 | }; 39 | widget.onChanged(_currentState); 40 | }); 41 | } 42 | 43 | Widget get _currentIcon { 44 | if (_currentState == true) { 45 | return widget.trueIcon; 46 | } else if (_currentState == false) { 47 | return widget.falseIcon ?? widget.trueIcon; 48 | } else { 49 | return widget.nullIcon ?? widget.falseIcon ?? widget.trueIcon; 50 | } 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | return IconButton( 56 | icon: _currentIcon, 57 | onPressed: _toggleState, 58 | color: Theme.of(context).iconTheme.color, 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | desktop_drop 7 | irondash_engine_context 8 | screen_retriever_linux 9 | sentry_flutter 10 | super_native_extensions 11 | url_launcher_linux 12 | window_manager 13 | window_size 14 | ) 15 | 16 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 17 | ) 18 | 19 | set(PLUGIN_BUNDLED_LIBRARIES) 20 | 21 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 23 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 26 | endforeach(plugin) 27 | 28 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 29 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 31 | endforeach(ffi_plugin) 32 | -------------------------------------------------------------------------------- /linux/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} 10 | "main.cc" 11 | "my_application.cc" 12 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 13 | ) 14 | 15 | # Apply the standard set of build settings. This can be removed for applications 16 | # that need different build settings. 17 | apply_standard_settings(${BINARY_NAME}) 18 | 19 | # Add preprocessor definitions for the application ID. 20 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 21 | 22 | # Add dependency libraries. Add any application-specific dependencies here. 23 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 24 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 25 | 26 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 27 | -------------------------------------------------------------------------------- /linux/runner/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /linux/runner/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import desktop_drop 9 | import device_info_plus 10 | import file_picker 11 | import flutter_inappwebview_macos 12 | import irondash_engine_context 13 | import package_info_plus 14 | import path_provider_foundation 15 | import screen_retriever_macos 16 | import sentry_flutter 17 | import super_native_extensions 18 | import url_launcher_macos 19 | import window_manager 20 | import window_size 21 | 22 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 23 | DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin")) 24 | DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) 25 | FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) 26 | InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) 27 | IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin")) 28 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) 29 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 30 | ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) 31 | SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) 32 | SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin")) 33 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 34 | WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) 35 | WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) 36 | } 37 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.15' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_macos_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = TriOS 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = org.wisp.TriOS 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2024 org.wisp. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 12 | com.apple.security.cs.allow-jit 13 | 14 | com.apple.security.network.server 15 | 16 | com.apple.security.network.client 17 | 18 | com.apple.security.files.user-selected.read-write 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 12 | com.apple.security.network.client 13 | 14 | com.apple.security.files.user-selected.read-write 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /readme_resources/chipper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/readme_resources/chipper.png -------------------------------------------------------------------------------- /readme_resources/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/readme_resources/dashboard.png -------------------------------------------------------------------------------- /readme_resources/jre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/readme_resources/jre.png -------------------------------------------------------------------------------- /readme_resources/rules_reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/readme_resources/rules_reload.png -------------------------------------------------------------------------------- /test/libarchive_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:trios/compression/libarchive/libarchive.dart'; 5 | import 'package:trios/utils/extensions.dart'; 6 | import 'package:trios/utils/logging.dart'; 7 | 8 | void main() { 9 | final currentDir = Directory.current; 10 | final assetsPath = Directory("${currentDir.path}/assets"); 11 | 12 | // Time taken: 0:00:00.332460 13 | test("LibArchive read test", () { 14 | configureLogging(); 15 | 16 | final time = DateTime.now(); 17 | final libArchive = LibArchive.fromPath(assetsPath); 18 | var archivePath = "F:/Downloads/Combat-Activators-v1.1.3.zip".toFile(); 19 | final archiveEntries = libArchive.listEntriesInArchive(archivePath); 20 | print("Time taken: ${DateTime.now().difference(time)}"); 21 | 22 | print("Archive file: $archivePath"); 23 | for (var element in archiveEntries) { 24 | print(element); 25 | print(element.file); 26 | } 27 | }); 28 | 29 | test("LibArchive extraction test", () async { 30 | configureLogging(); 31 | 32 | final time = DateTime.now(); 33 | final libArchive = LibArchive.fromPath(assetsPath); 34 | var archivePath = 35 | "F:/Downloads/OpenJDK-jdk_x64_windows_hotspot_24_26-ea.zip"; 36 | final archiveEntries = await libArchive.extractEntriesInArchive( 37 | File(archivePath), 38 | "F:/Downloads/extractTest", 39 | ); 40 | print("Time taken: ${DateTime.now().difference(time)}"); 41 | 42 | print("Extracting archive file: $archivePath"); 43 | for (var element in archiveEntries) { 44 | print(element); 45 | } 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:trios/main.dart'; 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(const TriOSApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | void RegisterPlugins(flutter::PluginRegistry* registry) { 20 | DesktopDropPluginRegisterWithRegistrar( 21 | registry->GetRegistrarForPlugin("DesktopDropPlugin")); 22 | FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( 23 | registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); 24 | IrondashEngineContextPluginCApiRegisterWithRegistrar( 25 | registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi")); 26 | ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( 27 | registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); 28 | SentryFlutterPluginRegisterWithRegistrar( 29 | registry->GetRegistrarForPlugin("SentryFlutterPlugin")); 30 | SuperNativeExtensionsPluginCApiRegisterWithRegistrar( 31 | registry->GetRegistrarForPlugin("SuperNativeExtensionsPluginCApi")); 32 | UrlLauncherWindowsRegisterWithRegistrar( 33 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 34 | WindowManagerPluginRegisterWithRegistrar( 35 | registry->GetRegistrarForPlugin("WindowManagerPlugin")); 36 | WindowSizePluginRegisterWithRegistrar( 37 | registry->GetRegistrarForPlugin("WindowSizePlugin")); 38 | } 39 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | desktop_drop 7 | flutter_inappwebview_windows 8 | irondash_engine_context 9 | screen_retriever_windows 10 | sentry_flutter 11 | super_native_extensions 12 | url_launcher_windows 13 | window_manager 14 | window_size 15 | ) 16 | 17 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 18 | ) 19 | 20 | set(PLUGIN_BUNDLED_LIBRARIES) 21 | 22 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 24 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 27 | endforeach(plugin) 28 | 29 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 30 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 31 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 32 | endforeach(ffi_plugin) 33 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"TriOS", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | 34 | // ChatGPT code until window.SetQuitOnClose(true); 35 | // Change background color here (RGB format) 36 | SetWindowLongPtr(window.GetHandle(), GWL_STYLE, GetWindowLongPtr(window.GetHandle(), GWL_STYLE) | WS_BORDER); 37 | HBRUSH backgroundBrush = CreateSolidBrush(RGB(0, 0, 0)); // Black background 38 | SetClassLongPtr(window.GetHandle(), GCLP_HBRBACKGROUND, (LONG_PTR)backgroundBrush); 39 | 40 | 41 | window.SetQuitOnClose(true); 42 | 43 | ::MSG msg; 44 | while (::GetMessage(&msg, nullptr, 0, 0)) { 45 | ::TranslateMessage(&msg); 46 | ::DispatchMessage(&msg); 47 | } 48 | 49 | ::CoUninitialize(); 50 | return EXIT_SUCCESS; 51 | } 52 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wispborne/TriOS/c8dc80a1f8cd5ee97d9973fc632c404d98c985d9/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | unsigned int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length == 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | --------------------------------------------------------------------------------