├── .github ├── file └── ISSUE_TEMPLATE │ └── config.yaml ├── .fvmrc ├── android ├── settings_aar.gradle ├── app │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── res │ │ ├── drawable-hdpi │ │ │ ├── splash.png │ │ │ ├── android12splash.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ ├── drawable-mdpi │ │ │ ├── splash.png │ │ │ ├── android12splash.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ ├── drawable │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ ├── drawable-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ ├── drawable-xhdpi │ │ │ ├── splash.png │ │ │ ├── android12splash.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ ├── drawable-xxhdpi │ │ │ ├── splash.png │ │ │ ├── android12splash.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ ├── drawable-xxxhdpi │ │ │ ├── splash.png │ │ │ ├── android12splash.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ ├── values │ │ │ └── colors.xml │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ ├── drawable-night-hdpi │ │ │ └── android12splash.png │ │ ├── drawable-night-mdpi │ │ │ └── android12splash.png │ │ ├── drawable-night-xhdpi │ │ │ └── android12splash.png │ │ ├── drawable-night-xxhdpi │ │ │ └── android12splash.png │ │ ├── drawable-night-xxxhdpi │ │ │ └── android12splash.png │ │ ├── xml │ │ │ ├── network_security_config.xml │ │ │ └── provider_paths.xml │ │ └── mipmap-anydpi-v26 │ │ │ └── launcher_icon.xml │ │ └── kotlin │ │ └── org │ │ └── thingsboard │ │ └── pe │ │ └── app │ │ ├── KeepAliveService.kt │ │ ├── TbWebCallbackActivity.kt │ │ └── MainActivity.kt ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-38x38@2x.png │ │ │ ├── Icon-App-38x38@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-50x50@1x.png │ │ │ ├── Icon-App-50x50@2x.png │ │ │ ├── Icon-App-57x57@1x.png │ │ │ ├── Icon-App-57x57@2x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-64x64@2x.png │ │ │ ├── Icon-App-64x64@3x.png │ │ │ ├── Icon-App-68x68@2x.png │ │ │ ├── Icon-App-72x72@1x.png │ │ │ ├── Icon-App-72x72@2x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ ├── Icon-App-Dark-20x20@2x.png │ │ │ ├── Icon-App-Dark-20x20@3x.png │ │ │ ├── Icon-App-Dark-29x29@2x.png │ │ │ ├── Icon-App-Dark-29x29@3x.png │ │ │ ├── Icon-App-Dark-38x38@2x.png │ │ │ ├── Icon-App-Dark-38x38@3x.png │ │ │ ├── Icon-App-Dark-40x40@2x.png │ │ │ ├── Icon-App-Dark-40x40@3x.png │ │ │ ├── Icon-App-Dark-60x60@2x.png │ │ │ ├── Icon-App-Dark-60x60@3x.png │ │ │ ├── Icon-App-Dark-64x64@2x.png │ │ │ ├── Icon-App-Dark-64x64@3x.png │ │ │ ├── Icon-App-Dark-68x68@2x.png │ │ │ ├── Icon-App-Dark-76x76@2x.png │ │ │ ├── Icon-App-Dark-1024x1024@1x.png │ │ │ └── Icon-App-Dark-83.5x83.5@2x.png │ │ └── LaunchBackground.imageset │ │ │ ├── background.png │ │ │ └── Contents.json │ ├── Runner.entitlements │ └── AppDelegate.swift ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ ├── TbDefault.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist └── .gitignore ├── lib ├── utils │ ├── services │ │ ├── user │ │ │ ├── i_user_service.dart │ │ │ └── user_service.dart │ │ ├── overlay_service │ │ │ ├── notification_type.dart │ │ │ └── i_overlay_service.dart │ │ ├── _tb_app_storage.dart │ │ ├── _tb_web_local_storage.dart │ │ ├── tb_app_storage.dart │ │ ├── permission │ │ │ ├── i_permission_service.dart │ │ │ └── permission_service.dart │ │ ├── communication │ │ │ ├── communication_event.dart │ │ │ ├── i_communication_service.dart │ │ │ ├── events │ │ │ │ ├── alarm_assignee_updated_event.dart │ │ │ │ ├── user_logged_in_event.dart │ │ │ │ ├── app_lifecycle_state_changed_event.dart │ │ │ │ └── device_provisioning_status_changed_event.dart │ │ │ └── communication_service.dart │ │ ├── provisioning │ │ │ ├── esp_smartconfig │ │ │ │ ├── i_esp_smartconfig_service.dart │ │ │ │ └── esp_smartconfig_service.dart │ │ │ ├── eps_ble │ │ │ │ └── i_wifi_provisioning_service.dart │ │ │ └── soft_ap │ │ │ │ └── i_soft_ap_service.dart │ │ ├── firebase │ │ │ └── i_firebase_service.dart │ │ ├── mobile_actions │ │ │ ├── results │ │ │ │ ├── image_result.dart │ │ │ │ ├── launch_result.dart │ │ │ │ ├── device_provisioning_result.dart │ │ │ │ ├── qr_code_result.dart │ │ │ │ └── location_result.dart │ │ │ ├── actions │ │ │ │ ├── show_map_with_directions_action.dart │ │ │ │ ├── take_photo_action.dart │ │ │ │ ├── make_phone_call_action.dart │ │ │ │ ├── unknown_action.dart │ │ │ │ ├── show_map_location_action.dart │ │ │ │ └── url_action.dart │ │ │ ├── widget_mobile_action_type.dart │ │ │ ├── mobile_action.dart │ │ │ └── widget_mobile_action_result.dart │ │ ├── device_profile │ │ │ └── model │ │ │ │ └── cached_device_profile.dart │ │ ├── device_info │ │ │ └── i_device_info_service.dart │ │ ├── local_database │ │ │ └── i_local_database_service.dart │ │ ├── layouts │ │ │ └── i_layout_service.dart │ │ └── endpoint │ │ │ └── i_endpoint_service.dart │ ├── usecase.dart │ ├── string_utils.dart │ └── ui │ │ ├── pagination_widgets │ │ ├── new_page_progress_builder.dart │ │ └── first_page_progress_builder.dart │ │ ├── back_button_widget.dart │ │ ├── ui_utils.dart │ │ ├── qr_code_scanner │ │ ├── scanner_error_widget.dart │ │ └── scan_area_clipper.dart │ │ └── tb_alert_dialog.dart ├── core │ ├── auth │ │ ├── login │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── auth_events.dart │ │ │ │ └── auth_states.dart │ │ │ └── di │ │ │ │ └── login_di.dart │ │ ├── noauth │ │ │ ├── presentation │ │ │ │ ├── bloc │ │ │ │ │ ├── bloc.dart │ │ │ │ │ ├── noauth_states.dart │ │ │ │ │ └── noauth_events.dart │ │ │ │ └── widgets │ │ │ │ │ ├── noauth_loading_widget.dart │ │ │ │ │ └── endpoint_name_widget.dart │ │ │ ├── domain │ │ │ │ └── repository │ │ │ │ │ └── i_noauth_repository.dart │ │ │ ├── data │ │ │ │ ├── datasource │ │ │ │ │ └── remote │ │ │ │ │ │ └── i_noauth_remote_datasource.dart │ │ │ │ └── model │ │ │ │ │ ├── switch_endpoint_args.dart │ │ │ │ │ └── switch_endpoint_args.g.dart │ │ │ └── routes │ │ │ │ └── noauth_routes.dart │ │ ├── oauth2 │ │ │ ├── i_oauth2_client.dart │ │ │ ├── tb_o_auth2_authenticate_result.dart │ │ │ └── app_secret_provider.dart │ │ └── web │ │ │ └── on_app_lifecycle_resume_observer.dart │ ├── logger │ │ ├── tb_log_output.dart │ │ └── tb_logs_filter.dart │ └── init │ │ ├── init_app.dart │ │ └── init_routes.dart ├── constants │ ├── hive_type_adapter_ids.dart │ ├── database_keys.dart │ ├── enviroment_variables.dart │ └── app_constants.dart ├── modules │ ├── alarm │ │ ├── presentation │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── assignee │ │ │ │ │ ├── bloc.dart │ │ │ │ │ └── assignee_state.dart │ │ │ │ ├── alarm_types │ │ │ │ │ ├── bloc.dart │ │ │ │ │ ├── alarm_types_state.dart │ │ │ │ │ └── alarm_types_event.dart │ │ │ │ ├── activity │ │ │ │ │ └── bloc.dart │ │ │ │ ├── alarm_details │ │ │ │ │ ├── bloc.dart │ │ │ │ │ ├── alarm_details_events.dart │ │ │ │ │ └── alarm_details_states.dart │ │ │ │ ├── alarm_assignee │ │ │ │ │ ├── bloc.dart │ │ │ │ │ └── alarm_assignee_state.dart │ │ │ │ ├── filters │ │ │ │ │ ├── filters │ │ │ │ │ │ ├── i_alarm_filter.dart │ │ │ │ │ │ ├── alarm_assignee_filter.dart │ │ │ │ │ │ ├── alarm_type_filter.dart │ │ │ │ │ │ └── alarm_severity_filter.dart │ │ │ │ │ └── i_alarm_filters_service.dart │ │ │ │ ├── alarms_states.dart │ │ │ │ └── alarms_events.dart │ │ │ └── widgets │ │ │ │ ├── details │ │ │ │ └── alarm_status_button.dart │ │ │ │ ├── activity │ │ │ │ ├── activity_builder_widget.dart │ │ │ │ └── system_activity_widget.dart │ │ │ │ └── assignee │ │ │ │ └── user_info_avatar_widget.dart │ │ ├── data │ │ │ ├── datasource │ │ │ │ ├── assignee │ │ │ │ │ ├── i_assignee_datasource.dart │ │ │ │ │ └── assignee_datasource.dart │ │ │ │ ├── alarm_types │ │ │ │ │ ├── i_alarm_types_datasource.dart │ │ │ │ │ └── alarm_types_datasource.dart │ │ │ │ ├── alarms │ │ │ │ │ ├── i_alarms_datasource.dart │ │ │ │ │ └── alarms_datasource.dart │ │ │ │ └── details │ │ │ │ │ └── i_alarm_details_datasource.dart │ │ │ └── repository │ │ │ │ ├── assignee │ │ │ │ └── assignee_repository.dart │ │ │ │ ├── alarm_types │ │ │ │ └── alarm_types_repository.dart │ │ │ │ └── alarms │ │ │ │ └── alarms_repository.dart │ │ ├── domain │ │ │ ├── repository │ │ │ │ ├── assignee │ │ │ │ │ └── i_assigne_repository.dart │ │ │ │ ├── alarm_types │ │ │ │ │ └── i_alarm_types_repository.dart │ │ │ │ ├── alarms │ │ │ │ │ └── i_alarms_repository.dart │ │ │ │ └── details │ │ │ │ │ └── i_alarm_details_repository.dart │ │ │ ├── entities │ │ │ │ ├── alarm_comment_entity.dart │ │ │ │ ├── filter_data_entity.dart │ │ │ │ └── assignee_entity.dart │ │ │ ├── usecases │ │ │ │ ├── alarms │ │ │ │ │ ├── fetch_alarm_usecase.dart │ │ │ │ │ └── fetch_alarms_usecase.dart │ │ │ │ ├── details │ │ │ │ │ ├── clear_alarm_usecase.dart │ │ │ │ │ ├── acknowledge_alarm_usecase.dart │ │ │ │ │ ├── fetch_alarm_comments_usecase.dart │ │ │ │ │ └── delete_alarm_comment_usecase.dart │ │ │ │ ├── assignee │ │ │ │ │ ├── unassign_alarm_usecase.dart │ │ │ │ │ └── assign_alarm_usecase.dart │ │ │ │ └── alarm_types │ │ │ │ │ └── fetch_alarm_types_usecase.dart │ │ │ └── pagination │ │ │ │ ├── alarm_types │ │ │ │ ├── alarm_types_query_ctrl.dart │ │ │ │ └── alarm_types_pagination_repository.dart │ │ │ │ ├── alarms │ │ │ │ └── alarms_pagination_repository.dart │ │ │ │ ├── activity │ │ │ │ ├── alarm_activity_pagination_repository.dart │ │ │ │ └── alarm_activity_query_ctrl.dart │ │ │ │ └── assignee │ │ │ │ ├── assignee_pagination_repository.dart │ │ │ │ ├── assignee_query_ctrl.dart │ │ │ │ ├── alarm_assignee_pagiation_repository.dart │ │ │ │ └── alarm_assignee_query_ctrl.dart │ │ └── alarms_base.dart │ ├── device │ │ ├── provisioning │ │ │ ├── ble │ │ │ │ ├── bloc │ │ │ │ │ ├── bloc.dart │ │ │ │ │ └── events.dart │ │ │ │ └── di │ │ │ │ │ └── esp_ble_di.dart │ │ │ ├── soft_ap │ │ │ │ ├── bloc │ │ │ │ │ └── bloc.dart │ │ │ │ └── di │ │ │ │ │ └── esp_softap_di.dart │ │ │ ├── models │ │ │ │ ├── provisioning_permission_type.dart │ │ │ │ ├── wifi_network.dart │ │ │ │ └── wifi_network.g.dart │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ └── device_provisioning_events.dart │ │ │ ├── view │ │ │ │ └── states │ │ │ │ │ ├── provision_states.dart │ │ │ │ │ ├── sending_wifi_credentials.dart │ │ │ │ │ ├── provision_error.dart │ │ │ │ │ ├── confirming_wifi_connection.dart │ │ │ │ │ ├── provision_success.dart │ │ │ │ │ ├── claiming_wip.dart │ │ │ │ │ ├── claiming_error.dart │ │ │ │ │ └── manually_reconnect_to_wifi.dart │ │ │ └── widgets │ │ │ │ ├── help_message_widget.dart │ │ │ │ ├── return_to_dashboard_button.dart │ │ │ │ ├── dotted_point_widget.dart │ │ │ │ └── try_again_button.dart │ │ ├── device_profiles_grid.dart │ │ ├── devices_list.dart │ │ ├── device_details_page.dart │ │ ├── devices_list_widget.dart │ │ └── devices_page.dart │ ├── layout_pages │ │ └── bloc │ │ │ ├── bloc.dart │ │ │ ├── layout_pages_state.dart │ │ │ └── layout_pages_event.dart │ ├── version │ │ ├── bloc │ │ │ ├── bloc.dart │ │ │ └── version_info_events.dart │ │ └── route │ │ │ ├── version_route_arguments.dart │ │ │ └── version_route.dart │ ├── notification │ │ ├── repository │ │ │ └── i_notification_query_repository.dart │ │ ├── service │ │ │ └── i_notifications_local_service.dart │ │ ├── usecase │ │ │ ├── handle_notification_tap_params.dart │ │ │ └── handle_notification_tap_usecase.dart │ │ ├── di │ │ │ └── notifcations_di.dart │ │ ├── routes │ │ │ └── notification_routes.dart │ │ └── widgets │ │ │ └── no_notifications_found_widget.dart │ ├── dashboard │ │ └── domain │ │ │ ├── pagination │ │ │ ├── dashboards_query_ctrl.dart │ │ │ └── dashboards_pagination_repository.dart │ │ │ ├── usecases │ │ │ └── fetch_dashboards_usecase.dart │ │ │ └── entites │ │ │ └── dashboard_arguments.dart │ ├── asset │ │ ├── assets_list.dart │ │ ├── assets_list_widget.dart │ │ └── asset_routes.dart │ ├── main │ │ ├── main_routes.dart │ │ ├── main_navigation_item.dart │ │ └── main_item_widget.dart │ ├── more │ │ └── more_routes.dart │ ├── tenant │ │ ├── tenants_list.dart │ │ ├── tenant_details_page.dart │ │ ├── tenants_base.dart │ │ ├── tenants_widget.dart │ │ └── tenant_routes.dart │ ├── audit_log │ │ ├── audit_logs_list.dart │ │ └── audit_logs_routes.dart │ ├── customer │ │ ├── customers_list.dart │ │ ├── customer_details_page.dart │ │ ├── customers_base.dart │ │ └── customer_routes.dart │ ├── home │ │ └── home_routes.dart │ ├── profile │ │ └── profile_routes.dart │ └── url │ │ └── url_routes.dart ├── config │ ├── themes │ │ └── app_colors.dart │ └── routes │ │ ├── tb_routes.dart │ │ └── route_not_found_widget.dart ├── thingsboard_client.dart ├── firebase_options.dart ├── app_bloc_observer.dart └── widgets │ └── two_value_listenable_builder.dart ├── assets ├── branding │ ├── splash.png │ ├── icon_filled.png │ ├── icon_foreground.png │ ├── icon_monochrome.png │ └── splash_android_12.png └── images │ ├── thingsboard.png │ ├── scan_rectangle.svg │ ├── email-verified.svg │ ├── facebook-logo.svg │ ├── github-logo.svg │ ├── email-verification.svg │ ├── qr_code_scanner.svg │ ├── google-logo.svg │ ├── scaner.svg │ └── apple-logo.svg ├── devtools_options.yaml ├── .metadata ├── flutter_native_splash.yaml ├── test └── mocks.dart ├── analysis_options.yaml ├── README.md └── .gitignore /.github/file: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.fvmrc: -------------------------------------------------------------------------------- 1 | { 2 | "flutter": "3.29.0" 3 | } -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yaml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/utils/services/user/i_user_service.dart: -------------------------------------------------------------------------------- 1 | abstract interface class IUserService {} 2 | -------------------------------------------------------------------------------- /lib/utils/services/overlay_service/notification_type.dart: -------------------------------------------------------------------------------- 1 | enum NotificationType { info, warn, success, error } -------------------------------------------------------------------------------- /assets/branding/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/assets/branding/splash.png -------------------------------------------------------------------------------- /lib/core/auth/login/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'auth_bloc.dart'; 2 | export 'auth_events.dart'; 3 | export 'auth_states.dart'; 4 | -------------------------------------------------------------------------------- /assets/images/thingsboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/assets/images/thingsboard.png -------------------------------------------------------------------------------- /lib/constants/hive_type_adapter_ids.dart: -------------------------------------------------------------------------------- 1 | abstract final class HiveTypeAdapterIds { 2 | static const regionAdapterId = 1; 3 | } 4 | -------------------------------------------------------------------------------- /assets/branding/icon_filled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/assets/branding/icon_filled.png -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'alarms_bloc.dart'; 2 | export 'alarms_events.dart'; 3 | export 'alarms_states.dart'; 4 | -------------------------------------------------------------------------------- /assets/branding/icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/assets/branding/icon_foreground.png -------------------------------------------------------------------------------- /assets/branding/icon_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/assets/branding/icon_monochrome.png -------------------------------------------------------------------------------- /assets/branding/splash_android_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/assets/branding/splash_android_12.png -------------------------------------------------------------------------------- /lib/core/auth/noauth/presentation/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'noauth_bloc.dart'; 2 | export 'noauth_events.dart'; 3 | export 'noauth_states.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/ble/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'eps_ble_provisioning_bloc.dart'; 2 | export 'events.dart'; 3 | export 'states.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/layout_pages/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'layout_pages_bloc.dart'; 2 | export 'layout_pages_event.dart'; 3 | export 'layout_pages_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/version/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'version_info_bloc.dart'; 2 | export 'version_info_events.dart'; 3 | export 'version_info_states.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/assignee/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'assignee_bloc.dart'; 2 | export 'assignee_event.dart'; 3 | export 'assignee_state.dart'; 4 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # The espressif library needs to have all their names and fields preserved. 2 | -keep,allowoptimization class espressif.* { *; } 3 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/soft_ap/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'esp_softap_bloc.dart'; 2 | export 'esp_softap_events.dart'; 3 | export 'esp_softap_states.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_types/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'alarm_types_bloc.dart'; 2 | export 'alarm_types_event.dart'; 3 | export 'alarm_types_state.dart'; 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /lib/utils/services/_tb_app_storage.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | TbStorage createAppStorage() => throw UnsupportedError(''); 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/activity/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'alarm_activity_bloc.dart'; 2 | export 'alarm_activity_events.dart'; 3 | export 'alarm_activity_states.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_details/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'alarm_details_bloc.dart'; 2 | export 'alarm_details_events.dart'; 3 | export 'alarm_details_states.dart'; 4 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/models/provisioning_permission_type.dart: -------------------------------------------------------------------------------- 1 | enum ProvisioningPermissionsType { 2 | bluetooth, 3 | nearbyDevices, 4 | wifi, 5 | location 6 | } -------------------------------------------------------------------------------- /lib/utils/services/_tb_web_local_storage.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | TbStorage createAppStorage() => throw UnimplementedError(); 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_assignee/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'alarm_assignee_bloc.dart'; 2 | export 'alarm_assignee_event.dart'; 3 | export 'alarm_assignee_state.dart'; 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /lib/utils/services/tb_app_storage.dart: -------------------------------------------------------------------------------- 1 | export '_tb_app_storage.dart' 2 | if (dart.library.io) '_tb_secure_storage.dart' 3 | if (dart.library.html) '_tb_web_local_storage.dart'; 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-hdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-mdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-hdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-night-hdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-mdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-night-mdpi/android12splash.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /lib/utils/usecase.dart: -------------------------------------------------------------------------------- 1 | abstract class UseCase { 2 | const UseCase(); 3 | 4 | Output call(Input params); 5 | } 6 | 7 | class NoParams { 8 | const NoParams(); 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-night-xhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-68x68@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-68x68@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | #include "TbDefault.xcconfig" 4 | #include "AppConfig.xcconfig" 5 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | #include "TbDefault.xcconfig" 4 | #include "AppConfig.xcconfig" 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-68x68@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-68x68@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsboard/flutter_thingsboard_pe_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-83.5x83.5@2x.png -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/filters/filters/i_alarm_filter.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract interface class IAlarmFilter { 3 | T getSelectedFilterData(); 4 | 5 | void updateSelectedData(T data); 6 | 7 | void reset(); 8 | } 9 | -------------------------------------------------------------------------------- /lib/utils/services/permission/i_permission_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/context/tb_context.dart'; 2 | 3 | abstract interface class IPermissionService { 4 | bool haveViewDashboardPermission(TbContext context); 5 | } 6 | -------------------------------------------------------------------------------- /ios/Flutter/TbDefault.xcconfig: -------------------------------------------------------------------------------- 1 | IOSAPPLICATIONID=org.thingsboard.pe.app 2 | IOSAPPLICATIONNAME=ThingsBoard Pe App 3 | REGISTRATIONREDIRECTURLHOST=app.pe.thingsboard.org 4 | REGISTRATIONREDIRECTURLSCHEME=tbscheme 5 | APPLINKSURLHOST=thingsboard.cloud -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | #kotlin.jvm.target.validation.mode = IGNORE 5 | 6 | -------------------------------------------------------------------------------- /lib/core/auth/oauth2/i_oauth2_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/auth/oauth2/tb_o_auth2_authenticate_result.dart'; 2 | abstract interface class IOAuth2Client { 3 | Future authenticate(String oauth2Url); 4 | } 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /lib/constants/database_keys.dart: -------------------------------------------------------------------------------- 1 | abstract final class DatabaseKeys { 2 | static const thingsBoardApiEndpointKey = 'thingsBoardApiEndpoint'; 3 | static const initialAppLink = 'initialAppLink'; 4 | static const selectedRegion = 'selectedRegion'; 5 | } 6 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/assignee/i_assignee_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAssigneeDatasource { 4 | Future> fetchAssignee(PageLink pageKey); 5 | } 6 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/repository/assignee/i_assigne_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAssigneeRepository { 4 | Future> fetchAssignee(PageLink pageKey); 5 | } 6 | -------------------------------------------------------------------------------- /lib/utils/services/communication/communication_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | base class CommunicationEvent extends Equatable { 4 | const CommunicationEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/alarm_types/i_alarm_types_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAlarmTypesDatasource { 4 | Future> fetchAlarmTypes(PageLink pageKey); 5 | } 6 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/repository/alarm_types/i_alarm_types_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAlarmTypesRepository { 4 | Future> fetchAlarmTypes(PageLink pageKey); 5 | } 6 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'device_provisioning_bloc.dart'; 2 | export 'device_provisioning_events.dart'; 3 | export 'device_provisioning_states.dart'; 4 | 5 | enum DeviceProvisioningStatus { idle, wifi, confirmation, success, fail, done } 6 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/provision_states.dart: -------------------------------------------------------------------------------- 1 | export 'claiming_error.dart'; 2 | export 'claiming_wip.dart'; 3 | export 'confirming_wifi_connection.dart'; 4 | export 'provision_error.dart'; 5 | export 'provision_success.dart'; 6 | export 'sending_wifi_credentials.dart'; 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jun 09 16:01:25 EEST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /assets/images/scan_rectangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/constants/enviroment_variables.dart: -------------------------------------------------------------------------------- 1 | abstract final class EnvironmentVariables { 2 | static const apiCalls = 3 | bool.fromEnvironment('API_CALLS'); 4 | static const verbose = bool.fromEnvironment('VERBOSE'); 5 | static const showAppVersion = bool.fromEnvironment('showAppVersion'); 6 | } 7 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/alarms/i_alarms_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAlarmsDatasource { 4 | Future> fetchAlarms(AlarmQueryV2 query); 5 | 6 | Future getAlarmInfo(String id); 7 | } 8 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/entities/alarm_comment_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | class AlarmCommentEntity { 4 | const AlarmCommentEntity(this.commentInfo, {required this.canEdit}); 5 | 6 | final AlarmCommentInfo commentInfo; 7 | final bool canEdit; 8 | } 9 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/repository/alarms/i_alarms_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAlarmsRepository { 4 | Future> fetchAlarms(AlarmQueryV2 query); 5 | 6 | Future getAlarmInfo(String id); 7 | } 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/utils/services/communication/i_communication_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/communication/communication_event.dart'; 2 | 3 | abstract interface class ICommunicationService { 4 | Stream on(); 5 | 6 | void fire(CommunicationEvent event); 7 | } 8 | -------------------------------------------------------------------------------- /lib/utils/string_utils.dart: -------------------------------------------------------------------------------- 1 | extension EmailValidator on String { 2 | bool isValidEmail() { 3 | return RegExp( 4 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$', 5 | ).hasMatch(this); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/core/logger/tb_log_output.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:logger/logger.dart'; 3 | 4 | class TbLogOutput extends LogOutput { 5 | @override 6 | void output(OutputEvent event) { 7 | for (final line in event.lines) { 8 | debugPrint(line); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | debug.jks -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.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: adc687823a831bbebe28bdccfac1a628ca621513 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /lib/core/auth/oauth2/tb_o_auth2_authenticate_result.dart: -------------------------------------------------------------------------------- 1 | class TbOAuth2AuthenticateResult { 2 | 3 | TbOAuth2AuthenticateResult.success(this.accessToken, this.refreshToken); 4 | 5 | TbOAuth2AuthenticateResult.failed(this.error); 6 | String? accessToken; 7 | String? refreshToken; 8 | String? error; 9 | 10 | bool get success => error == null; 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/services/communication/events/alarm_assignee_updated_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/communication/communication_event.dart'; 2 | 3 | final class AlarmAssigneeUpdatedEvent extends CommunicationEvent { 4 | const AlarmAssigneeUpdatedEvent(this.id); 5 | 6 | final String? id; 7 | 8 | @override 9 | List get props => [id]; 10 | } 11 | -------------------------------------------------------------------------------- /flutter_native_splash.yaml: -------------------------------------------------------------------------------- 1 | flutter_native_splash: 2 | color: "##ffffff" 3 | image: assets/branding/splash.png 4 | android_12: 5 | image: assets/branding/splash_android_12.png 6 | color: "#ffffff" 7 | icon_background_color: "#ffffff" 8 | android: true 9 | ios: true 10 | info_plist_files: 11 | - 'ios/Runner/Info-Debug.plist' 12 | - 'ios/Runner/Info-Release.plist' -------------------------------------------------------------------------------- /lib/modules/version/route/version_route_arguments.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart' 2 | show StoreInfo, VersionInfo; 3 | 4 | class VersionRouteArguments { 5 | const VersionRouteArguments({ 6 | required this.versionInfo, 7 | required this.storeInfo, 8 | }); 9 | 10 | final VersionInfo versionInfo; 11 | final StoreInfo? storeInfo; 12 | } 13 | -------------------------------------------------------------------------------- /lib/utils/services/provisioning/esp_smartconfig/i_esp_smartconfig_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:esp_smartconfig/esp_smartconfig.dart'; 2 | 3 | enum SmartConfig { espTouch, espTouchV2 } 4 | 5 | abstract interface class IEspSmartConfigService { 6 | Provisioner create(SmartConfig config); 7 | 8 | Future start(ProvisioningRequest request); 9 | 10 | Future stop(); 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/services/firebase/i_firebase_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_core/firebase_core.dart'; 2 | 3 | abstract interface class IFirebaseService { 4 | const IFirebaseService(); 5 | 6 | Future initializeApp({String name, FirebaseOptions? options}); 7 | 8 | Future removeApp({String name}); 9 | Future clearApps(); 10 | List get apps; 11 | } 12 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/modules/notification/repository/i_notification_query_repository.dart: -------------------------------------------------------------------------------- 1 | abstract interface class INotificationQueryRepository { 2 | Future markAllAsRead(); 3 | 4 | Future markNotificationAsRead(String id); 5 | 6 | Future deleteNotification(String id); 7 | 8 | Future searchNotification(String searchText); 9 | 10 | Future filterByReadStatus(bool unreadOnly); 11 | } 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/modules/notification/service/i_notifications_local_service.dart: -------------------------------------------------------------------------------- 1 | abstract interface class INotificationsLocalService { 2 | Future increaseNotificationBadgeCount(); 3 | 4 | Future decreaseNotificationBadgeCount(); 5 | 6 | Future triggerNotificationCountStream(); 7 | 8 | Future clearNotificationBadgeCount(); 9 | 10 | Future updateNotificationsCount(int count); 11 | } 12 | -------------------------------------------------------------------------------- /lib/modules/notification/usecase/handle_notification_tap_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/context/tb_context.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class HandleNotificationTapParams { 5 | HandleNotificationTapParams( 6 | {required this.notification, required this.tbContext}); 7 | 8 | final PushNotification notification; 9 | final TbContext tbContext; 10 | } 11 | -------------------------------------------------------------------------------- /lib/utils/services/communication/events/user_logged_in_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart' show User; 2 | import 'package:thingsboard_app/utils/services/communication/communication_event.dart'; 3 | 4 | final class UserLoggedInEvent extends CommunicationEvent { 5 | const UserLoggedInEvent(this.user); 6 | 7 | final User? user; 8 | 9 | @override 10 | List get props => [user]; 11 | } 12 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/org/thingsboard/pe/app/KeepAliveService.kt: -------------------------------------------------------------------------------- 1 | package org.thingsboard.pe.app 2 | 3 | import android.app.Service 4 | import android.content.Intent 5 | import android.os.Binder 6 | import android.os.IBinder 7 | 8 | class KeepAliveService: Service() { 9 | companion object { 10 | val binder = Binder() 11 | } 12 | 13 | override fun onBind(intent: Intent): IBinder { 14 | return binder 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/config/themes/app_colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppColors { 4 | AppColors._(); 5 | static const textPrimary = Color(0xDE000000); 6 | static const cameraBackground = Color(0xFF828282); 7 | static const iconSecondary = Color(0xC2000000); 8 | static const textWhite = Color(0xFFFFFFFF); 9 | static const textTertiary = Color(0x8A000000); 10 | static const black = Color(0xFF000000); 11 | } 12 | -------------------------------------------------------------------------------- /lib/modules/dashboard/domain/pagination/dashboards_query_ctrl.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class DashboardsQueryCtrl extends PageKeyController { 5 | DashboardsQueryCtrl() : super(PageLink(20)); 6 | 7 | @override 8 | PageLink nextPageKey(PageLink pageKey) { 9 | return pageKey.nextPageLink(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/results/image_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 2 | 3 | class ImageResult extends MobileActionResult { 4 | 5 | ImageResult(this.imageUrl); 6 | String imageUrl; 7 | 8 | @override 9 | Map toJson() { 10 | final json = super.toJson(); 11 | json['imageUrl'] = imageUrl; 12 | return json; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/results/launch_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 2 | 3 | class LaunchResult extends MobileActionResult { 4 | 5 | LaunchResult(this.launched); 6 | bool launched; 7 | 8 | @override 9 | Map toJson() { 10 | final json = super.toJson(); 11 | json['launched'] = launched; 12 | return json; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/core/auth/web/on_app_lifecycle_resume_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class OnAppLifecycleResumeObserver extends WidgetsBindingObserver { 4 | 5 | OnAppLifecycleResumeObserver(this.onResumed); 6 | final VoidCallback onResumed; 7 | 8 | @override 9 | void didChangeAppLifecycleState(AppLifecycleState state) { 10 | if (state == AppLifecycleState.resumed) { 11 | onResumed(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/entities/filter_data_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class FilterDataEntity extends Equatable { 5 | const FilterDataEntity( { required this.getLocalizedLabel, required this.data}); 6 | 7 | 8 | final T data; 9 | final String Function(BuildContext context) getLocalizedLabel; 10 | @override 11 | List get props => [ data]; 12 | } 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/utils/services/communication/events/app_lifecycle_state_changed_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart' show AppLifecycleState; 2 | import 'package:thingsboard_app/utils/services/communication/communication_event.dart'; 3 | 4 | 5 | final class AppLifecycleStateChangedEvent extends CommunicationEvent { 6 | const AppLifecycleStateChangedEvent(this.state); 7 | 8 | final AppLifecycleState state; 9 | 10 | @override 11 | List get props => [state]; 12 | } 13 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarms_states.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | sealed class AlarmsState extends Equatable { 4 | const AlarmsState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | final class AlarmsFiltersNotActivatedState extends AlarmsState { 11 | const AlarmsFiltersNotActivatedState(); 12 | } 13 | 14 | final class AlarmsFilterActivatedState extends AlarmsState { 15 | const AlarmsFilterActivatedState(); 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/results/device_provisioning_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 2 | 3 | class DeviceProvisioningResult extends MobileActionResult { 4 | DeviceProvisioningResult(this.deviceName); 5 | 6 | final String deviceName; 7 | 8 | @override 9 | Map toJson() { 10 | final json = super.toJson(); 11 | json['deviceName'] = deviceName; 12 | return json; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/results/qr_code_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 2 | 3 | class QrCodeResult extends MobileActionResult { 4 | 5 | QrCodeResult(this.code, this.format); 6 | String code; 7 | String format; 8 | 9 | @override 10 | Map toJson() { 11 | final json = super.toJson(); 12 | json['code'] = code; 13 | json['format'] = format; 14 | return json; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/thingsboard_client.dart: -------------------------------------------------------------------------------- 1 | /// Since the CE and PE versions are mergeable, we frequently encounter merge 2 | /// conflicts due to the different names of the Dart client. 3 | /// The purpose of this file is to resolve these conflicts. 4 | /// 5 | /// By exporting the TB Client here, we ensure a consistent name for the client 6 | /// throughout the project. This file will change rarely, 7 | /// thus minimizing merge conflicts. 8 | library; 9 | 10 | export 'package:thingsboard_pe_client/thingsboard_client.dart'; 11 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/actions/show_map_with_directions_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/actions/show_map_location_action.dart'; 2 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_type.dart'; 3 | 4 | class ShowMapWithDirectionsAction extends ShowMapLocationAction { 5 | @override 6 | WidgetMobileActionType get type => WidgetMobileActionType.mapDirection; 7 | @override 8 | Future getUrl(List args) => getMapUrl(args, true); 9 | } -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/results/location_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 2 | 3 | class LocationResult extends MobileActionResult { 4 | 5 | LocationResult(this.latitude, this.longitude); 6 | num latitude; 7 | num longitude; 8 | 9 | @override 10 | Map toJson() { 11 | final json = super.toJson(); 12 | json['latitude'] = latitude; 13 | json['longitude'] = longitude; 14 | return json; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/ui/pagination_widgets/new_page_progress_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NewPageProgressBuilder extends StatelessWidget { 4 | const NewPageProgressBuilder({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return const Padding( 9 | padding: EdgeInsets.only( 10 | top: 16, 11 | bottom: 16, 12 | ), 13 | child: Center( 14 | child: RefreshProgressIndicator(), 15 | ), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/core/logger/tb_logs_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:logger/logger.dart'; 3 | import 'package:thingsboard_app/constants/enviroment_variables.dart'; 4 | 5 | class TbLogsFilter extends LogFilter { 6 | @override 7 | bool shouldLog(LogEvent event) { 8 | if (EnvironmentVariables.verbose) { 9 | return true; 10 | } else if (kReleaseMode) { 11 | return event.level.index >= Level.warning.index; 12 | } else { 13 | return true; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/ui/back_button_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class BackButtonWidget extends StatelessWidget { 6 | const BackButtonWidget({this.onPressed, super.key}); 7 | 8 | final VoidCallback? onPressed; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return IconButton( 13 | onPressed: onPressed, 14 | icon: Icon( 15 | Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back, 16 | ), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/utils/services/user/user_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/locator.dart'; 2 | import 'package:thingsboard_app/utils/services/communication/events/user_logged_in_event.dart'; 3 | import 'package:thingsboard_app/utils/services/communication/i_communication_service.dart'; 4 | import 'package:thingsboard_app/utils/services/user/i_user_service.dart'; 5 | 6 | class UserService implements IUserService { 7 | UserService() { 8 | getIt().on().listen((user) {}); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/utils/services/device_profile/model/cached_device_profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | part 'cached_device_profile.freezed.dart'; 4 | @freezed 5 | abstract class CachedDeviceProfileInfo with _$CachedDeviceProfileInfo { 6 | 7 | const factory CachedDeviceProfileInfo( 8 | { 9 | required int? activeCount, 10 | required int? inactiveCount, 11 | required DeviceProfileInfo info 12 | } 13 | ) = _CachedDeviceProfileInfo; 14 | } -------------------------------------------------------------------------------- /lib/utils/services/permission/permission_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/context/tb_context.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/services/permission/i_permission_service.dart'; 4 | 5 | class PermissionService implements IPermissionService { 6 | @override 7 | bool haveViewDashboardPermission(TbContext context) { 8 | return context.hasGenericPermission( 9 | Resource.DASHBOARD, 10 | Operation.READ, 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /assets/images/email-verified.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "LaunchImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LaunchImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/constants/app_constants.dart: -------------------------------------------------------------------------------- 1 | abstract final class ThingsboardAppConstants { 2 | static const thingsBoardApiEndpoint = String.fromEnvironment('thingsboardApiEndpoint'); 3 | static const thingsboardOAuth2CallbackUrlScheme = String.fromEnvironment('thingsboardOAuth2CallbackUrlScheme'); 4 | static const thingsboardIOSAppSecret = String.fromEnvironment('thingsboardIosAppSecret'); 5 | static const thingsboardAndroidAppSecret = String.fromEnvironment('thingsboardAndroidAppSecret'); 6 | static const ignoreRegionSelection = thingsBoardApiEndpoint != ''; 7 | } 8 | -------------------------------------------------------------------------------- /lib/modules/asset/assets_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_list.dart'; 3 | import 'package:thingsboard_app/modules/asset/assets_base.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class AssetsList extends BaseEntitiesWidget 7 | with AssetsBase, EntitiesListStateBase { 8 | AssetsList( 9 | super.tbContext, 10 | super.pageKeyController, { 11 | super.key, 12 | super.searchMode, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/services/communication/events/device_provisioning_status_changed_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/device/provisioning/bloc/bloc.dart' show DeviceProvisioningStatus; 2 | import 'package:thingsboard_app/utils/services/communication/communication_event.dart'; 3 | 4 | final class DeviceProvisioningStatusChangedEvent extends CommunicationEvent { 5 | const DeviceProvisioningStatusChangedEvent(this.status); 6 | 7 | final DeviceProvisioningStatus status; 8 | 9 | @override 10 | List get props => [double.nan]; 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/services/device_info/i_device_info_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:device_info_plus/device_info_plus.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | abstract interface class IDeviceInfoService { 5 | String getApplicationId(); 6 | String getDeviceModel(); 7 | String getSystemVersion(); 8 | PlatformType getPlatformType(); 9 | bool isPhysicalDevice(); 10 | PlatformVersion getAppVersion(); 11 | AndroidDeviceInfo? getAndroidDeviceInfo(); 12 | IosDeviceInfo? getIosDeviceInfo(); 13 | String getBuildVersion(); 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/actions/take_photo_action.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:image_picker/image_picker.dart'; 3 | import 'package:thingsboard_app/utils/services/mobile_actions/actions/take_picture_from_gallery_action.dart'; 4 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_type.dart'; 5 | 6 | class TakePhotoAction extends TakePictureFromGalleryAction { 7 | @override 8 | ImageSource get imageSource => ImageSource.camera; 9 | @override 10 | WidgetMobileActionType get type => WidgetMobileActionType.takePhoto; 11 | } -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/assignee/assignee_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/data/datasource/assignee/i_assignee_datasource.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AssigneeDatasource implements IAssigneeDatasource { 5 | const AssigneeDatasource({required this.tbClient}); 6 | 7 | final ThingsboardClient tbClient; 8 | 9 | @override 10 | Future> fetchAssignee(PageLink pageKey) { 11 | return tbClient.getUserService().getUsersInfo(pageKey); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/modules/main/main_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 3 | import 'package:thingsboard_app/modules/main/main_page.dart'; 4 | 5 | class MainRoutes extends TbRoutes { 6 | MainRoutes(super.tbContext); 7 | 8 | @override 9 | void doRegisterRoutes(FluroRouter router) { 10 | router.define( 11 | '/main', 12 | handler: Handler( 13 | handlerFunc: (context, params) { 14 | return MainPage(tbContext); 15 | }, 16 | ), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/more/more_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 3 | import 'package:thingsboard_app/modules/more/more_page.dart'; 4 | 5 | class MoreRoutes extends TbRoutes { 6 | 7 | MoreRoutes(super.tbContext); 8 | late final moreHandler = Handler( 9 | handlerFunc: (context, params) { 10 | return MorePage(tbContext); 11 | }, 12 | ); 13 | 14 | @override 15 | void doRegisterRoutes(FluroRouter router) { 16 | router.define('/more', handler: moreHandler); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/modules/version/bloc/version_info_events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/modules/version/route/version_route_arguments.dart'; 3 | 4 | sealed class VersionInfoEvent extends Equatable { 5 | const VersionInfoEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class VersionInfoFetchEvent extends VersionInfoEvent { 12 | const VersionInfoFetchEvent(this.args); 13 | 14 | final VersionRouteArguments args; 15 | 16 | @override 17 | List get props => [args]; 18 | } 19 | -------------------------------------------------------------------------------- /lib/config/routes/tb_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/router.dart'; 3 | import 'package:thingsboard_app/core/context/tb_context.dart'; 4 | import 'package:thingsboard_app/locator.dart'; 5 | 6 | abstract class TbRoutes { 7 | 8 | TbRoutes(this._tbContext); 9 | final TbContext _tbContext; 10 | 11 | void registerRoutes() { 12 | doRegisterRoutes(getIt().router); 13 | } 14 | 15 | void doRegisterRoutes(FluroRouter router); 16 | 17 | TbContext get tbContext => _tbContext; 18 | } 19 | -------------------------------------------------------------------------------- /lib/utils/services/provisioning/eps_ble/i_wifi_provisioning_service.dart: -------------------------------------------------------------------------------- 1 | abstract interface class IBleProvisioningService { 2 | Future> scanBleDevices(String prefix); 3 | 4 | Future> scanWifiNetworks({ 5 | required String deviceName, 6 | required String proofOfPossession, 7 | }); 8 | 9 | Future provisionWifi({ 10 | required String deviceName, 11 | required String proofOfPossession, 12 | required String ssid, 13 | required String passphrase, 14 | }); 15 | 16 | Future getPlatformVersion(); 17 | } 18 | -------------------------------------------------------------------------------- /lib/modules/tenant/tenants_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_list.dart'; 3 | import 'package:thingsboard_app/modules/tenant/tenants_base.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class TenantsList extends BaseEntitiesWidget 7 | with TenantsBase, ContactBasedBase, EntitiesListStateBase { 8 | TenantsList( 9 | super.tbContext, 10 | super.pageKeyController, { 11 | super.searchMode, 12 | super.key, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/org/thingsboard/pe/app/TbWebCallbackActivity.kt: -------------------------------------------------------------------------------- 1 | package org.thingsboard.pe.app 2 | 3 | import android.app.Activity 4 | import android.net.Uri 5 | import android.os.Bundle 6 | 7 | class TbWebCallbackActivity: Activity() { 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | 11 | val url = intent?.data 12 | val scheme = url?.scheme 13 | 14 | if (scheme != null) { 15 | TbWebAuthHandler.callbacks.remove(scheme)?.success(url.toString()) 16 | } 17 | 18 | finish() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/alarm_types/alarm_types_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/data/datasource/alarm_types/i_alarm_types_datasource.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AlarmTypesDatasource implements IAlarmTypesDatasource { 5 | const AlarmTypesDatasource({required this.tbClient}); 6 | 7 | final ThingsboardClient tbClient; 8 | 9 | @override 10 | Future> fetchAlarmTypes(PageLink pageKey) { 11 | return tbClient.getAlarmService().getAlarmTypes(pageKey); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/modules/audit_log/audit_logs_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_list.dart'; 3 | import 'package:thingsboard_app/modules/audit_log/audit_logs_base.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class AuditLogsList extends BaseEntitiesWidget 7 | with AuditLogsBase, EntitiesListStateBase { 8 | AuditLogsList( 9 | super.tbContext, 10 | super.pageKeyController, { 11 | super.searchMode, 12 | super.key, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/device/device_profiles_grid.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_grid.dart'; 3 | import 'package:thingsboard_app/modules/device/device_profiles_base.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class DeviceProfilesGrid extends BaseEntitiesWidget 7 | with DeviceProfilesBase, EntitiesGridStateBase { 8 | DeviceProfilesGrid( 9 | super.tbContext, 10 | super.pageKeyController, { 11 | super.key, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/sending_wifi_credentials.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/view/states/connection_state_row.dart'; 4 | 5 | class SendingWifiCredentials extends StatelessWidget { 6 | const SendingWifiCredentials({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return ConnectionStateRow( 11 | S.of(context).sendingWifiCredentials, 12 | inProgress: true, 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/modules/notification/di/notifcations_di.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/locator.dart'; 2 | import 'package:thingsboard_app/modules/notification/usecase/handle_notification_tap_usecase.dart'; 3 | 4 | abstract final class NotifcationsDi { 5 | static const _scopeName = 'NotifcationsDi'; 6 | static void init() { 7 | getIt.pushNewScope( 8 | scopeName: _scopeName, 9 | init: (getIt) => 10 | getIt.registerFactory(() => HandleNotificationTapUsecase()), 11 | ); 12 | } 13 | 14 | static void dispose() { 15 | getIt.dropScope(_scopeName); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/widget_mobile_action_type.dart: -------------------------------------------------------------------------------- 1 | enum WidgetMobileActionType { 2 | takePictureFromGallery, 3 | takePhoto, 4 | mapDirection, 5 | mapLocation, 6 | scanQrCode, 7 | makePhoneCall, 8 | getLocation, 9 | takeScreenshot, 10 | deviceProvision, 11 | unknown; 12 | 13 | static WidgetMobileActionType fromString(String value) { 14 | return WidgetMobileActionType.values.firstWhere( 15 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase(), 16 | orElse: () => WidgetMobileActionType.unknown, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/alarms/fetch_alarm_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/alarms/i_alarms_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | class FetchAlarmUseCase extends UseCase, String> { 6 | const FetchAlarmUseCase({required this.repository}); 7 | 8 | final IAlarmsRepository repository; 9 | 10 | @override 11 | Future call(String params) { 12 | return repository.getAlarmInfo(params); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/customer/customers_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_list.dart'; 3 | import 'package:thingsboard_app/modules/customer/customers_base.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class CustomersList extends BaseEntitiesWidget 7 | with CustomersBase, ContactBasedBase, EntitiesListStateBase { 8 | CustomersList( 9 | super.tbContext, 10 | super.pageKeyController, { 11 | super.key, 12 | super.searchMode, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/dashboard/domain/usecases/fetch_dashboards_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | import 'package:thingsboard_app/utils/usecase.dart'; 3 | 4 | class FetchDashboardsUseCase 5 | extends UseCase>, PageLink> { 6 | const FetchDashboardsUseCase(this.tbClient); 7 | 8 | final ThingsboardClient tbClient; 9 | 10 | @override 11 | Future> call(PageLink params) { 12 | return tbClient 13 | .getDashboardService() 14 | .getUserDashboards(params, mobile: true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.associated-domains 8 | 9 | 10 | com.apple.developer.networking.HotspotConfiguration 11 | 12 | com.apple.developer.networking.wifi-info 13 | 14 | com.apple.security.network.client 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/details/clear_alarm_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/details/i_alarm_details_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | final class ClearAlarmUseCase extends UseCase, AlarmId> { 6 | const ClearAlarmUseCase(this.repository); 7 | 8 | final IAlarmDetailsRepository repository; 9 | 10 | @override 11 | Future call(AlarmId params) { 12 | return repository.clearAlarm(params); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/config/routes/route_not_found_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | 4 | class RouteNotFoundWidget extends StatelessWidget { 5 | const RouteNotFoundWidget({ 6 | super.key, 7 | required this.settings, 8 | }); 9 | 10 | final RouteSettings? settings; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(title: Text(S.of(context).notFound)), 16 | body: Center(child: Text(S.of(context).routeNotDefined(settings?.name ?? ''))), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/alarm/alarms_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | extension AlarmSeverityColors on AlarmSeverity { 5 | Color toColor() { 6 | return switch (this) { 7 | AlarmSeverity.CRITICAL => const Color(0xFFD12730), 8 | 9 | AlarmSeverity.MAJOR => const Color(0xFFF66716), 10 | 11 | AlarmSeverity.MINOR => const Color(0xFFF2DA05), 12 | 13 | AlarmSeverity.WARNING => const Color(0xFFFAA405), 14 | 15 | AlarmSeverity.INDETERMINATE => Colors.black.withValues(alpha: 0.38), 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/modules/tenant/tenant_details_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entity_details_page.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class TenantDetailsPage extends ContactBasedDetailsPage { 5 | TenantDetailsPage(super.tbContext, String tenantId, {super.key}) 6 | : super( 7 | entityId: tenantId, 8 | defaultTitle: 'Tenant', 9 | subTitle: 'Tenant details', 10 | ); 11 | 12 | @override 13 | Future fetchEntity(String id) { 14 | return tbClient.getTenantService().getTenant(id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/assignee/unassign_alarm_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/details/i_alarm_details_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | final class UnassignAlarmUseCase extends UseCase, String> { 6 | const UnassignAlarmUseCase(this.repository); 7 | 8 | final IAlarmDetailsRepository repository; 9 | 10 | @override 11 | Future call(String params) { 12 | return repository.unassignAlarm(params); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/home/home_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 4 | import 'package:thingsboard_app/modules/home/home_page.dart'; 5 | 6 | class HomeRoutes extends TbRoutes { 7 | HomeRoutes(super.tbContext); 8 | late Handler homeHandler = Handler( 9 | handlerFunc: (BuildContext? context, params) { 10 | return HomePage(tbContext); 11 | }, 12 | ); 13 | 14 | @override 15 | void doRegisterRoutes(FluroRouter router) { 16 | router.define('/home', handler: homeHandler); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /assets/images/facebook-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/alarms/fetch_alarms_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/alarms/i_alarms_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | class FetchAlarmsUseCase 6 | extends UseCase>, AlarmQueryV2> { 7 | const FetchAlarmsUseCase({required this.repository}); 8 | 9 | final IAlarmsRepository repository; 10 | 11 | @override 12 | Future> call(AlarmQueryV2 params) { 13 | return repository.fetchAlarms(params); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/details/acknowledge_alarm_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/details/i_alarm_details_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | final class AcknowledgeAlarmUseCase 6 | extends UseCase, AlarmId> { 7 | const AcknowledgeAlarmUseCase(this.repository); 8 | 9 | final IAlarmDetailsRepository repository; 10 | 11 | @override 12 | Future call(AlarmId params) { 13 | return repository.acknowledgeAlarm(params); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/modules/customer/customer_details_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entity_details_page.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class CustomerDetailsPage extends ContactBasedDetailsPage { 5 | CustomerDetailsPage(super.tbContext, String customerId, {super.key}) 6 | : super( 7 | entityId: customerId, 8 | defaultTitle: 'Customer', 9 | subTitle: 'Customer details', 10 | ); 11 | 12 | @override 13 | Future fetchEntity(String id) { 14 | return tbClient.getCustomerService().getCustomer(id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/core/auth/login/bloc/auth_events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart' show PlatformType; 3 | 4 | sealed class AuthEvent extends Equatable { 5 | const AuthEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class AuthFetchEvent extends AuthEvent { 12 | const AuthFetchEvent({ 13 | required this.packageName, 14 | required this.platformType, 15 | }); 16 | 17 | final String packageName; 18 | final PlatformType platformType; 19 | 20 | @override 21 | List get props => [packageName, platformType]; 22 | } 23 | -------------------------------------------------------------------------------- /test/mocks.dart: -------------------------------------------------------------------------------- 1 | import 'package:mocktail/mocktail.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | import 'package:thingsboard_app/utils/services/endpoint/endpoint_service.dart'; 5 | import 'package:thingsboard_app/utils/services/firebase/firebase_service.dart'; 6 | 7 | class MockTbContext extends Mock implements TbContext {} 8 | 9 | class MockTbClient extends Mock implements ThingsboardClient {} 10 | 11 | class MockFirebaseService extends Mock implements FirebaseService {} 12 | 13 | class MockEndpointService extends Mock implements EndpointService {} 14 | -------------------------------------------------------------------------------- /lib/modules/dashboard/domain/entites/dashboard_arguments.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | /// This class represents the arguments a user can pass to open a dashboard 4 | class DashboardArgumentsEntity extends Equatable { 5 | const DashboardArgumentsEntity( 6 | this.id, { 7 | this.title, 8 | this.state, 9 | this.hideToolbar, 10 | this.animate = true, 11 | }); 12 | 13 | final String id; 14 | final String? title; 15 | final String? state; 16 | final bool? hideToolbar; 17 | final bool animate; 18 | 19 | @override 20 | List get props => [id, title, state, hideToolbar, animate]; 21 | } 22 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lint/strict.yaml 2 | analyzer: 3 | plugins: 4 | - custom_lint 5 | exclude: 6 | - '**.freezed.dart' 7 | - '**.g.dart' 8 | - "**/*.gform.dart" 9 | - "**/messages_*.dart" 10 | errors: 11 | invalid_annotation_target: ignore 12 | linter: 13 | rules: 14 | # Util classes are awesome! 15 | avoid_classes_with_only_static_members: false 16 | eol_at_end_of_file: false 17 | require_trailing_commas: false 18 | use_setters_to_change_properties: false 19 | sort_pub_dependencies: false 20 | # Make constructors the first thing in every class 21 | sort_constructors_first: true -------------------------------------------------------------------------------- /assets/images/github-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/repository/assignee/assignee_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/data/datasource/assignee/i_assignee_datasource.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/repository/assignee/i_assigne_repository.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | 5 | class AssigneeRepository implements IAssigneeRepository { 6 | const AssigneeRepository({required this.datasource}); 7 | 8 | final IAssigneeDatasource datasource; 9 | 10 | @override 11 | Future> fetchAssignee(PageLink pageKey) { 12 | return datasource.fetchAssignee(pageKey); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/alarm_types/fetch_alarm_types_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/alarm_types/i_alarm_types_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | class FetchAlarmTypesUseCase 6 | extends UseCase>, PageLink> { 7 | const FetchAlarmTypesUseCase({required this.repository}); 8 | 9 | final IAlarmTypesRepository repository; 10 | 11 | @override 12 | Future> call(PageLink params) { 13 | return repository.fetchAlarmTypes(params); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/images/email-verification.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/soft_ap/di/esp_softap_di.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/locator.dart'; 2 | import 'package:thingsboard_app/utils/services/provisioning/soft_ap/i_soft_ap_service.dart'; 3 | import 'package:thingsboard_app/utils/services/provisioning/soft_ap/soft_ap_service.dart'; 4 | 5 | abstract final class EspSoftApDi { 6 | static void init(String scopeName) { 7 | getIt.pushNewScope( 8 | scopeName: scopeName, 9 | init: (locator) { 10 | locator.registerFactory(() => SoftApService()); 11 | }, 12 | ); 13 | } 14 | 15 | static void dispose(String scopeName) { 16 | getIt.dropScope(scopeName); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/utils/ui/pagination_widgets/first_page_progress_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FirstPageProgressBuilder extends StatelessWidget { 4 | const FirstPageProgressBuilder({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return const Stack( 9 | children: [ 10 | Positioned( 11 | top: 20, 12 | left: 0, 13 | right: 0, 14 | child: Row( 15 | mainAxisAlignment: MainAxisAlignment.center, 16 | children: [ 17 | RefreshProgressIndicator(), 18 | ], 19 | ), 20 | ), 21 | ], 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/modules/asset/assets_list_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/config/routes/router.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_list_widget.dart'; 3 | import 'package:thingsboard_app/locator.dart'; 4 | import 'package:thingsboard_app/modules/asset/assets_base.dart'; 5 | import 'package:thingsboard_app/thingsboard_client.dart'; 6 | 7 | class AssetsListWidget extends EntitiesListPageLinkWidget 8 | with AssetsBase { 9 | AssetsListWidget( 10 | super.tbContext, { 11 | super.key, 12 | super.controller, 13 | }); 14 | 15 | @override 16 | void onViewAll() { 17 | getIt().navigateTo('/assets'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/layout_pages/bloc/layout_pages_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/modules/main/main_navigation_item.dart'; 3 | 4 | sealed class LayoutPagesState extends Equatable { 5 | const LayoutPagesState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class BottomBarLoadingState extends LayoutPagesState { 12 | const BottomBarLoadingState(); 13 | } 14 | 15 | final class BottomBarDataState extends LayoutPagesState { 16 | const BottomBarDataState({required this.items}); 17 | 18 | final List items; 19 | 20 | @override 21 | List get props => [items]; 22 | } 23 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/repository/alarm_types/alarm_types_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/data/datasource/alarm_types/i_alarm_types_datasource.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/repository/alarm_types/i_alarm_types_repository.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | 5 | class AlarmTypesRepository implements IAlarmTypesRepository { 6 | const AlarmTypesRepository({required this.datasource}); 7 | 8 | final IAlarmTypesDatasource datasource; 9 | 10 | @override 11 | Future> fetchAlarmTypes(PageLink pageKey) { 12 | return datasource.fetchAlarmTypes(pageKey); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/details/fetch_alarm_comments_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/details/i_alarm_details_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | class FetchAlarmCommentsUseCase 6 | extends UseCase>, AlarmCommentsQuery> { 7 | const FetchAlarmCommentsUseCase(this.repository); 8 | 9 | final IAlarmDetailsRepository repository; 10 | 11 | @override 12 | Future> call(AlarmCommentsQuery params) { 13 | return repository.fetchAlarmComments(params); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/modules/layout_pages/bloc/layout_pages_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | sealed class LayoutPagesEvent extends Equatable { 5 | const LayoutPagesEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class BottomBarFetchEvent extends LayoutPagesEvent { 12 | const BottomBarFetchEvent(this.context); 13 | 14 | final BuildContext context; 15 | } 16 | 17 | final class BottomBarOrientationChangedEvent extends LayoutPagesEvent { 18 | const BottomBarOrientationChangedEvent(this.orientation, this.screenSize); 19 | 20 | final Orientation orientation; 21 | final Size screenSize; 22 | } 23 | -------------------------------------------------------------------------------- /lib/utils/services/local_database/i_local_database_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/auth/login/select_region/model/region.dart'; 2 | 3 | /// The aim of this service is to consolidate operations with 4 | /// the local database provider into one centralized location. 5 | 6 | abstract interface class ILocalDatabaseService { 7 | Future getSelectedRegion(); 8 | 9 | Future saveSelectedRegion(Region region); 10 | 11 | Future getSelectedEndpoint(); 12 | 13 | Future setSelectedEndpoint(String endpoint); 14 | 15 | Future setInitialAppLink(String appLink); 16 | 17 | Future getInitialAppLink(); 18 | 19 | Future deleteInitialAppLink(); 20 | } 21 | -------------------------------------------------------------------------------- /lib/modules/notification/routes/notification_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 3 | import 'package:thingsboard_app/modules/notification/notification_page.dart'; 4 | 5 | class NotificationRoutes extends TbRoutes { 6 | NotificationRoutes(super.tbContext); 7 | 8 | static const notificationRoutePath = '/notifications'; 9 | 10 | late final notificationHandler = Handler( 11 | handlerFunc: (context, params) { 12 | return NotificationPage(tbContext); 13 | }, 14 | ); 15 | 16 | @override 17 | void doRegisterRoutes(FluroRouter router) { 18 | router.define(notificationRoutePath, handler: notificationHandler); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/utils/services/communication/communication_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:event_bus/event_bus.dart'; 2 | import 'package:thingsboard_app/utils/services/communication/communication_event.dart'; 3 | import 'package:thingsboard_app/utils/services/communication/i_communication_service.dart'; 4 | 5 | class CommunicationService implements ICommunicationService { 6 | const CommunicationService(EventBus eventBus) : _eventBus = eventBus; 7 | 8 | final EventBus _eventBus; 9 | 10 | @override 11 | void fire(CommunicationEvent event) { 12 | _eventBus.fire(event); 13 | } 14 | 15 | @override 16 | Stream on() { 17 | return _eventBus.on(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | Flutter/AppConfig.xcconfig 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/alarms/alarms_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/data/datasource/alarms/i_alarms_datasource.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AlarmsDatasource implements IAlarmsDatasource { 5 | const AlarmsDatasource({required this.thingsboardClient}); 6 | 7 | final ThingsboardClient thingsboardClient; 8 | 9 | @override 10 | Future> fetchAlarms(AlarmQueryV2 query) { 11 | return thingsboardClient.getAlarmService().getAllAlarmsV2(query); 12 | } 13 | 14 | @override 15 | Future getAlarmInfo(String id) { 16 | return thingsboardClient.getAlarmService().getAlarmInfo(id); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/presentation/widgets/noauth_loading_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context.dart'; 3 | import 'package:thingsboard_app/widgets/tb_progress_indicator.dart'; 4 | 5 | class NoAuthLoadingWidget extends StatelessWidget { 6 | const NoAuthLoadingWidget({required this.tbContext, super.key}); 7 | 8 | final TbContext tbContext; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return SizedBox.expand( 13 | child: ColoredBox( 14 | color: const Color(0x99FFFFFF), 15 | child: Center( 16 | child: TbProgressIndicator(tbContext, size: 50.0), 17 | ), 18 | ), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_assignee/alarm_assignee_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/entities/assignee_entity.dart'; 3 | 4 | sealed class AlarmAssigneeState extends Equatable { 5 | const AlarmAssigneeState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class AlarmAssigneeEmptyState extends AlarmAssigneeState { 12 | const AlarmAssigneeEmptyState(); 13 | } 14 | 15 | final class AlarmAssigneeSelectedState extends AlarmAssigneeState { 16 | const AlarmAssigneeSelectedState(this.assignee); 17 | 18 | final AssigneeEntity assignee; 19 | 20 | @override 21 | List get props => [assignee]; 22 | } 23 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/ble/di/esp_ble_di.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/locator.dart'; 2 | import 'package:thingsboard_app/utils/services/provisioning/eps_ble/i_wifi_provisioning_service.dart'; 3 | import 'package:thingsboard_app/utils/services/provisioning/eps_ble/wifi_provisioning_service.dart'; 4 | 5 | abstract final class EspBleDi { 6 | static void init(String scopeName) { 7 | getIt.pushNewScope( 8 | scopeName: scopeName, 9 | init: (locator) { 10 | locator.registerFactory( 11 | () => BleProvisioningService(), 12 | ); 13 | }, 14 | ); 15 | } 16 | 17 | static void dispose(String scopeName) { 18 | getIt.dropScope(scopeName); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/modules/profile/profile_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 4 | 5 | import 'package:thingsboard_app/modules/profile/profile_page.dart'; 6 | 7 | class ProfileRoutes extends TbRoutes { 8 | ProfileRoutes(super.tbContext); 9 | late final profileHandler = Handler( 10 | handlerFunc: (BuildContext? context, params) { 11 | final fullscreen = params['fullscreen']?.first == 'true'; 12 | return ProfilePage(tbContext, fullscreen: fullscreen); 13 | }, 14 | ); 15 | 16 | @override 17 | void doRegisterRoutes(FluroRouter router) { 18 | router.define('/profile', handler: profileHandler); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/modules/url/url_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 3 | import 'package:thingsboard_app/modules/url/url_page.dart'; 4 | 5 | class UrlPageRoutes extends TbRoutes { 6 | UrlPageRoutes(super.tbContext); 7 | 8 | static const urlPageRoutes = '/url/:link'; 9 | 10 | late final urlPageHandler = Handler( 11 | handlerFunc: (context, params) { 12 | return UrlPage( 13 | url: Uri.decodeQueryComponent(params['link']?.first ?? ''), 14 | tbContext: tbContext, 15 | ); 16 | }, 17 | ); 18 | 19 | @override 20 | void doRegisterRoutes(FluroRouter router) { 21 | router.define(urlPageRoutes, handler: urlPageHandler); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/filters/i_alarm_filters_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/entities/alarm_filters_entity.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/entities/filter_data_entity.dart'; 3 | 4 | enum Filters { status, severity, type, assignee } 5 | 6 | abstract interface class IAlarmFiltersService { 7 | List get statuses; 8 | 9 | List get severities; 10 | 11 | AlarmFiltersEntity getCommittedFilters(); 12 | 13 | void commitChanges(); 14 | 15 | void reset(); 16 | 17 | void resetUnCommittedChanges(); 18 | 19 | T getSelectedFilter(Filters type); 20 | 21 | void setSelectedFilter(Filters type, {required T data}); 22 | } 23 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/alarm_types/alarm_types_query_ctrl.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AlarmTypesQueryCtrl extends PageKeyController { 5 | AlarmTypesQueryCtrl({ 6 | int pageSize = 20, 7 | String? searchText, 8 | SortOrder? sortOrder, 9 | }) : super( 10 | PageLink( 11 | pageSize, 12 | 0, 13 | searchText, 14 | sortOrder, 15 | ), 16 | ); 17 | 18 | @override 19 | PageLink nextPageKey(PageLink pageKey) { 20 | return pageKey.nextPageLink(); 21 | } 22 | 23 | void refresh() { 24 | notifyListeners(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/modules/device/devices_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_list.dart'; 3 | import 'package:thingsboard_app/modules/device/devices_base.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class DevicesList extends BaseEntitiesWidget 7 | with DevicesBase, EntitiesListStateBase { 8 | 9 | DevicesList( 10 | super.tbContext, 11 | super.pageKeyController, { 12 | super.key, 13 | super.searchMode, 14 | this.displayDeviceImage = false, 15 | }); 16 | final bool displayDeviceImage; 17 | 18 | @override 19 | bool displayCardImage(bool listWidgetCard) => displayDeviceImage; 20 | } 21 | -------------------------------------------------------------------------------- /lib/modules/audit_log/audit_logs_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 4 | import 'package:thingsboard_app/modules/audit_log/audit_logs_page.dart'; 5 | 6 | class AuditLogsRoutes extends TbRoutes { 7 | AuditLogsRoutes(super.tbContext); 8 | late final auditLogsHandler = Handler( 9 | handlerFunc: (BuildContext? context, params) { 10 | final searchMode = params['search']?.first == 'true'; 11 | return AuditLogsPage(tbContext, searchMode: searchMode); 12 | }, 13 | ); 14 | 15 | @override 16 | void doRegisterRoutes(FluroRouter router) { 17 | router.define('/auditLogs', handler: auditLogsHandler); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/repository/alarms/alarms_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/data/datasource/alarms/i_alarms_datasource.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/repository/alarms/i_alarms_repository.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | 5 | class AlarmsRepository implements IAlarmsRepository { 6 | const AlarmsRepository({required this.datasource}); 7 | 8 | final IAlarmsDatasource datasource; 9 | 10 | @override 11 | Future> fetchAlarms(AlarmQueryV2 query) { 12 | return datasource.fetchAlarms(query); 13 | } 14 | 15 | @override 16 | Future getAlarmInfo(String id) { 17 | return datasource.getAlarmInfo(id); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/notification/widgets/no_notifications_found_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | 4 | class NoNotificationsFoundWidget extends StatelessWidget { 5 | const NoNotificationsFoundWidget({super.key}); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Center( 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | Text( 14 | S.of(context).noNotificationsFound, 15 | style: const TextStyle( 16 | fontWeight: FontWeight.w400, 17 | fontSize: 16, 18 | ), 19 | ), 20 | ], 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/modules/device/device_details_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/core/entity/entity_details_page.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | 5 | class DeviceDetailsPage extends EntityDetailsPage { 6 | DeviceDetailsPage(super.tbContext, String deviceId, {super.key}) 7 | : super(entityId: deviceId, defaultTitle: 'Device'); 8 | 9 | @override 10 | Future fetchEntity(String id) { 11 | return tbClient.getDeviceService().getDevice(id); 12 | } 13 | 14 | @override 15 | Widget buildEntityDetails(BuildContext context, Device entity) { 16 | return ListTile( 17 | title: Text(entity.name), 18 | subtitle: Text(entity.type), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/utils/ui/ui_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 3 | 4 | abstract class UiUtils { 5 | static Future showModalBottomSheet({ 6 | required BuildContext context, 7 | required WidgetBuilder builder, 8 | Color barrierColor = Colors.black54, 9 | Widget? topControl, 10 | }) { 11 | return showBarModalBottomSheet( 12 | context: context, 13 | builder: builder, 14 | barrierColor: barrierColor, 15 | topControl: topControl, 16 | ); 17 | } 18 | 19 | static Color colorFromString(String str) { 20 | return HSLColor.fromAHSL( 21 | 1, 22 | str.hashCode % 360, 23 | 40 / 100, 24 | 60 / 100, 25 | ).toColor(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/org/thingsboard/pe/app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package org.thingsboard.pe.app 2 | 3 | import androidx.annotation.NonNull 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugin.common.MethodChannel 7 | 8 | class MainActivity: FlutterActivity() { 9 | 10 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 11 | super.configureFlutterEngine(flutterEngine) 12 | registerTbWebAuth(flutterEngine) 13 | } 14 | 15 | fun registerTbWebAuth(flutterEngine: FlutterEngine) { 16 | val channel = MethodChannel(flutterEngine.dartExecutor, "tb_web_auth") 17 | channel.setMethodCallHandler(TbWebAuthHandler(this)) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /lib/firebase_options.dart: -------------------------------------------------------------------------------- 1 | // File generated by FlutterFire CLI. 2 | // ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members 3 | import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; 4 | 5 | /// Default [FirebaseOptions] for use with your Firebase apps. 6 | /// 7 | /// Example: 8 | /// ```dart 9 | /// import 'firebase_options.dart'; 10 | /// // ... 11 | /// await Firebase.initializeApp( 12 | /// options: DefaultFirebaseOptions.currentPlatform, 13 | /// ); 14 | /// ``` 15 | class DefaultFirebaseOptions { 16 | static FirebaseOptions get currentPlatform { 17 | throw UnsupportedError( 18 | 'Firebase have not been configured - ' 19 | 'you can reconfigure this by running the FlutterFire CLI again.', 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/domain/repository/i_noauth_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | abstract interface class INoAuthRepository { 5 | Future getJwtToken({ 6 | required String host, 7 | required String key, 8 | }); 9 | 10 | Future setUserFromJwtToken(LoginResponse loginData); 11 | 12 | Future logout({RequestConfig? requestConfig, bool notifyUser = true}); 13 | 14 | Future reInit({ 15 | required String endpoint, 16 | required VoidCallback onDone, 17 | required ErrorCallback onError, 18 | }); 19 | 20 | bool isAuthenticated(); 21 | 22 | AuthUser getAuthUserFromJwt(String jwt); 23 | 24 | AuthUser? getCurrentlyAuthenticatedUserOrNull(); 25 | } 26 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_types/alarm_types_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | sealed class AlarmTypesState extends Equatable { 4 | const AlarmTypesState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | final class AlarmTypeSelectedState extends AlarmTypesState { 11 | const AlarmTypeSelectedState({ 12 | required this.selectedTypes, 13 | required this.allowToAddMore, 14 | }); 15 | 16 | final Set selectedTypes; 17 | final bool allowToAddMore; 18 | 19 | @override 20 | List get props => [double.nan]; 21 | } 22 | 23 | final class AlarmTypesSelectionEmptyState extends AlarmTypesState { 24 | const AlarmTypesSelectionEmptyState(); 25 | 26 | @override 27 | List get props => []; 28 | } 29 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/widgets/details/alarm_status_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 3 | 4 | class AlarmStatusButton extends StatelessWidget { 5 | const AlarmStatusButton({required this.text, required this.onTap, super.key}); 6 | 7 | final String text; 8 | final VoidCallback? onTap; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return ElevatedButton( 13 | onPressed: onTap, 14 | child: Padding( 15 | padding: const EdgeInsets.all(10), 16 | child: Text( 17 | text, 18 | style: TbTextStyles.titleXs, 19 | maxLines: 1, 20 | overflow: TextOverflow.ellipsis, 21 | ), 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/provision_error.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/view/states/connection_state_row.dart'; 4 | 5 | class ProvisionError extends StatelessWidget { 6 | const ProvisionError({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | ConnectionStateRow( 13 | S.of(context).sendingWifiCredentials, 14 | inProgress: false, 15 | ), 16 | ConnectionStateRow( 17 | S.of(context).confirmingWifiConnection, 18 | inProgress: false, 19 | error: true, 20 | ), 21 | ], 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/confirming_wifi_connection.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/view/states/connection_state_row.dart'; 4 | 5 | class ConfirmingWifiConnection extends StatelessWidget { 6 | const ConfirmingWifiConnection({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | ConnectionStateRow( 13 | S.of(context).sendingWifiCredentials, 14 | inProgress: false, 15 | ), 16 | ConnectionStateRow( 17 | S.of(context).confirmingWifiConnection, 18 | inProgress: true, 19 | ), 20 | ], 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/modules/tenant/tenants_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/config/routes/router.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 3 | import 'package:thingsboard_app/locator.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | mixin TenantsBase on EntitiesBase { 7 | @override 8 | String get title => 'Tenants'; 9 | 10 | @override 11 | String get noItemsFoundText => 'No tenants found'; 12 | 13 | @override 14 | Future> fetchEntities(PageLink pageLink, {bool refresh = false}) { 15 | return tbClient.getTenantService().getTenants(pageLink); 16 | } 17 | 18 | @override 19 | void onEntityTap(Tenant tenant) { 20 | getIt().navigateTo('/tenant/${tenant.id!.id}'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /assets/images/qr_code_scanner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/data/datasource/remote/i_noauth_remote_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | abstract interface class INoAuthRemoteDatasource { 5 | Future getJwtToken({ 6 | required String host, 7 | required String key, 8 | }); 9 | 10 | Future setUserFromJwtToken(LoginResponse loginData); 11 | 12 | Future logout({RequestConfig? requestConfig, bool notifyUser = true}); 13 | 14 | Future reInit({ 15 | required String endpoint, 16 | required VoidCallback onDone, 17 | required ErrorCallback onError, 18 | }); 19 | 20 | bool isAuthenticated(); 21 | 22 | AuthUser getAuthUserFromJwt(String jwt); 23 | 24 | AuthUser? getCurrentlyAuthenticatedUserOrNull(); 25 | } 26 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/assignee/assignee_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/entities/assignee_entity.dart'; 3 | 4 | sealed class AssigneeState extends Equatable { 5 | const AssigneeState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class AssigneeEmptyState extends AssigneeState { 12 | const AssigneeEmptyState(); 13 | } 14 | 15 | final class AssigneeSelectedState extends AssigneeState { 16 | const AssigneeSelectedState({required this.assignee}); 17 | 18 | final AssigneeEntity assignee; 19 | 20 | @override 21 | List get props => [assignee]; 22 | } 23 | 24 | final class AssigneeSelfAssignmentState extends AssigneeState { 25 | const AssigneeSelfAssignmentState(); 26 | } 27 | -------------------------------------------------------------------------------- /assets/images/google-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/alarms/alarms_pagination_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/pagination/alarms/alarms_query_ctrl.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/services/pagination_repository.dart'; 4 | 5 | final class AlarmsPaginationRepository 6 | extends PaginationRepository { 7 | AlarmsPaginationRepository({ 8 | required AlarmQueryController queryController, 9 | required this.onFetchData, 10 | }) : super(pageKeyController: queryController); 11 | 12 | final Future> Function(AlarmQueryV2 query) onFetchData; 13 | 14 | @override 15 | Future> fetchPageData(AlarmQueryV2 pageKey) { 16 | return onFetchData(pageKey); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/modules/customer/customers_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/config/routes/router.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 3 | import 'package:thingsboard_app/locator.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | mixin CustomersBase on EntitiesBase { 7 | @override 8 | String get title => 'Customers'; 9 | 10 | @override 11 | String get noItemsFoundText => 'No customers found'; 12 | 13 | @override 14 | Future> fetchEntities(PageLink pageLink, {bool refresh = false}) { 15 | return tbClient.getCustomerService().getCustomers(pageLink); 16 | } 17 | 18 | @override 19 | void onEntityTap(Customer customer) { 20 | getIt().navigateTo('/customer/${customer.id!.id}'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/modules/dashboard/domain/pagination/dashboards_pagination_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/dashboard/domain/pagination/dashboards_query_ctrl.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/services/pagination_repository.dart'; 4 | 5 | final class DashboardsPaginationRepository 6 | extends PaginationRepository { 7 | DashboardsPaginationRepository({ 8 | required DashboardsQueryCtrl queryController, 9 | required this.onFetchData, 10 | }) : super(pageKeyController: queryController); 11 | 12 | final Future> Function(PageLink query) onFetchData; 13 | 14 | @override 15 | Future> fetchPageData(PageLink pageKey) { 16 | return onFetchData(pageKey); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/models/wifi_network.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | // required: associates our `main.dart` with the code generated by Freezed 5 | part 'wifi_network.freezed.dart'; 6 | // optional: Since our Person class is serializable, we must add this line. 7 | // But if Person was not serializable, we could skip it. 8 | part 'wifi_network.g.dart'; 9 | 10 | @freezed 11 | abstract class WifiNetwork with _$WifiNetwork { 12 | const factory WifiNetwork({ 13 | required String ssid, 14 | required int rssi, 15 | required int channel, 16 | // required Uint8List bssid, 17 | required String auth, 18 | @Default('') String password, 19 | }) = _WifiNetwork; 20 | 21 | factory WifiNetwork.fromJson(Map json) => _$WifiNetworkFromJson(json); 22 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [ThingsBoard PE Mobile Application](https://thingsboard.io/products/mobile-pe/) is an open-source project based on [Flutter](https://flutter.dev/) 2 | Powered by [ThingsBoard PE](https://thingsboard.io/products/thingsboard-pe/) IoT Platform 3 | 4 | Build your own advanced IoT mobile application **with minimum coding efforts** 5 | 6 | ## Please be informed the Web platform is not supported, because it's a part of our main platform! 7 | 8 | ## Resources 9 | 10 | - [Getting started](https://thingsboard.io/docs/pe/mobile/getting-started/) - learn how to set up and run your first IoT mobile app 11 | - [Customize your app](https://thingsboard.io/docs/pe/mobile/customization/) - learn how to customize the app 12 | - [Publish your app](https://thingsboard.io/docs/pe/mobile/release/) - learn how to publish app to Google Play or App Store 13 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/assignee/assign_alarm_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/details/i_alarm_details_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | class AssignAlarmUseCase extends UseCase, AssignAlarmParams> { 6 | const AssignAlarmUseCase(this.repository); 7 | 8 | final IAlarmDetailsRepository repository; 9 | 10 | @override 11 | Future call(AssignAlarmParams params) { 12 | return repository.assignAlarm(params.id, params.userId); 13 | } 14 | } 15 | 16 | final class AssignAlarmParams { 17 | const AssignAlarmParams({ 18 | required this.id, 19 | required this.userId, 20 | }); 21 | 22 | final String id; 23 | final String userId; 24 | } 25 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/actions/make_phone_call_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/actions/url_action.dart'; 2 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_type.dart'; 3 | 4 | class MakePhoneCallAction extends UrlAction { 5 | 6 | @override 7 | WidgetMobileActionType get type => WidgetMobileActionType.makePhoneCall; 8 | String _makePhoneCall(List args) { 9 | try { 10 | dynamic phoneNumber; 11 | if (args.length > 1 && args[1] != null) { 12 | phoneNumber = args[1]; 13 | } else { 14 | return ''; 15 | } 16 | return 'tel://$phoneNumber'; 17 | } catch (e) { 18 | return ''; 19 | } 20 | } 21 | 22 | @override 23 | Future getUrl(List args) async => _makePhoneCall(args); 24 | } 25 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/data/model/switch_endpoint_args.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'switch_endpoint_args.freezed.dart'; 4 | part 'switch_endpoint_args.g.dart'; 5 | 6 | @freezed 7 | abstract class SwitchEndpointArgs with _$SwitchEndpointArgs { 8 | const factory SwitchEndpointArgs( 9 | {required String secret, 10 | String? host, 11 | String? ttl, 12 | @JsonKey(fromJson: fromFluroData, toJson: uriToJson) 13 | required Uri uri}) = _SwitchEndpointArgs; 14 | 15 | factory SwitchEndpointArgs.fromJson(Map json) => 16 | _$SwitchEndpointArgsFromJson(json); 17 | } 18 | Uri fromFluroData(dynamic data) { 19 | if(data is Uri) { 20 | return data; 21 | } 22 | return Uri.parse(data.toString()); 23 | } 24 | String uriToJson(Uri uri) { 25 | return uri.toString(); 26 | } -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/alarm_types/alarm_types_pagination_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/pagination/alarm_types/alarm_types_query_ctrl.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/services/pagination_repository.dart'; 4 | 5 | final class AlarmTypesPaginationRepository 6 | extends PaginationRepository { 7 | AlarmTypesPaginationRepository({ 8 | required AlarmTypesQueryCtrl alarmTypesQueryCtrl, 9 | required this.onFetchPageData, 10 | }) : super(pageKeyController: alarmTypesQueryCtrl); 11 | 12 | final Future> Function(PageLink) onFetchPageData; 13 | 14 | @override 15 | Future> fetchPageData(PageLink pageKey) { 16 | return onFetchPageData(pageKey); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/widgets/activity/activity_builder_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/modules/alarm/presentation/widgets/activity/system_activity_widget.dart'; 3 | import 'package:thingsboard_app/modules/alarm/presentation/widgets/activity/user_comment_widget.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | class ActivityBuilderWidget extends StatelessWidget { 7 | const ActivityBuilderWidget(this.activity, {required this.userId, super.key}); 8 | 9 | final AlarmCommentInfo activity; 10 | final UserId userId; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | if (activity.type == AlarmCommentType.OTHER) { 15 | return UserCommentWidget(activity, userId: userId); 16 | } 17 | 18 | return SystemActivityWidget(activity); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/modules/version/route/version_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 3 | import 'package:thingsboard_app/modules/version/route/version_route_arguments.dart'; 4 | import 'package:thingsboard_app/modules/version/view/update_required_page.dart'; 5 | 6 | class VersionRoutes extends TbRoutes { 7 | VersionRoutes(super.tbContext); 8 | 9 | static const updateRequiredRoutePath = '/updateRequired'; 10 | 11 | late final updateRequiredHandler = Handler( 12 | handlerFunc: (context, params) { 13 | final args = context!.settings!.arguments! as VersionRouteArguments; 14 | return UpdateRequiredPage(tbContext, arguments: args); 15 | }, 16 | ); 17 | 18 | @override 19 | void doRegisterRoutes(FluroRouter router) { 20 | router.define(updateRequiredRoutePath, handler: updateRequiredHandler); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/init/init_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context_widget.dart'; 3 | import 'package:thingsboard_app/widgets/tb_progress_indicator.dart'; 4 | 5 | class ThingsboardInitApp extends TbPageWidget { 6 | ThingsboardInitApp(super.tbContext, {super.key}); 7 | 8 | @override 9 | State createState() => _ThingsboardInitAppState(); 10 | } 11 | 12 | class _ThingsboardInitAppState extends TbPageState { 13 | @override 14 | void initState() { 15 | super.initState(); 16 | initTbContext(); 17 | } 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Scaffold( 22 | body: Container( 23 | alignment: Alignment.center, 24 | color: Colors.white, 25 | child: TbProgressIndicator(tbContext, size: 50.0), 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/data/model/switch_endpoint_args.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'switch_endpoint_args.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _SwitchEndpointArgs _$SwitchEndpointArgsFromJson(Map json) => 10 | _SwitchEndpointArgs( 11 | secret: json['secret'] as String, 12 | host: json['host'] as String?, 13 | ttl: json['ttl'] as String?, 14 | uri: fromFluroData(json['uri']), 15 | ); 16 | 17 | Map _$SwitchEndpointArgsToJson(_SwitchEndpointArgs instance) => 18 | { 19 | 'secret': instance.secret, 20 | 'host': instance.host, 21 | 'ttl': instance.ttl, 22 | 'uri': uriToJson(instance.uri), 23 | }; 24 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/activity/alarm_activity_pagination_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/pagination/activity/alarm_activity_query_ctrl.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/services/pagination_repository.dart'; 4 | 5 | final class AlarmActivityPaginationRepository 6 | extends PaginationRepository { 7 | AlarmActivityPaginationRepository({ 8 | required AlarmActivityQueryCtrl queryCtrl, 9 | required this.onFetchPageData, 10 | }) : super(pageKeyController: queryCtrl); 11 | 12 | final Future> Function(AlarmCommentsQuery) 13 | onFetchPageData; 14 | 15 | @override 16 | Future> fetchPageData(AlarmCommentsQuery pageKey) { 17 | return onFetchPageData(pageKey); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/device/devices_list_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/config/routes/router.dart'; 2 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 3 | import 'package:thingsboard_app/core/entity/entities_list_widget.dart'; 4 | import 'package:thingsboard_app/locator.dart'; 5 | import 'package:thingsboard_app/modules/device/devices_base.dart'; 6 | import 'package:thingsboard_app/thingsboard_client.dart'; 7 | 8 | class DevicesListWidget extends EntitiesListWidget 9 | with DevicesBase { 10 | DevicesListWidget( 11 | super.tbContext, { 12 | super.key, 13 | super.controller, 14 | }); 15 | 16 | @override 17 | void onViewAll() { 18 | getIt().navigateTo('/devices'); 19 | } 20 | 21 | @override 22 | PageKeyController createPageKeyController() => 23 | DeviceQueryController(pageSize: 5); 24 | } 25 | -------------------------------------------------------------------------------- /lib/utils/services/provisioning/soft_ap/i_soft_ap_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data' show Uint8List; 2 | 3 | import 'package:esp_provisioning_softap/esp_provisioning_softap.dart'; 4 | 5 | abstract interface class ISoftApService { 6 | Future startProvisioning({ 7 | required String hostname, 8 | required String pop, 9 | }); 10 | 11 | Future>?> startScanWiFi(Provisioning prov); 12 | 13 | Future sendReceiveCustomData( 14 | Provisioning prov, { 15 | required Uint8List data, 16 | int packageSize = 256, 17 | String endpoint = 'custom-data', 18 | }); 19 | 20 | Future sendWifiConfig( 21 | Provisioning prov, { 22 | required String ssid, 23 | required String password, 24 | }); 25 | 26 | Future applyWifiConfig(Provisioning prov); 27 | 28 | Future getStatus(Provisioning prov); 29 | } 30 | -------------------------------------------------------------------------------- /lib/utils/ui/qr_code_scanner/scanner_error_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_hooks/flutter_hooks.dart'; 3 | import 'package:flutter_svg/flutter_svg.dart'; 4 | import 'package:thingsboard_app/config/themes/app_colors.dart'; 5 | 6 | class ScannerErrorWidget extends HookWidget { 7 | const ScannerErrorWidget({ 8 | super.key, 9 | }); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Material( 14 | color: Colors.transparent, 15 | child: SizedBox.expand( 16 | child: ColoredBox( 17 | color: AppColors.cameraBackground, 18 | child: Stack( 19 | children: [ 20 | Center( 21 | child: SvgPicture.asset('assets/images/scaner.svg'), 22 | ), 23 | ], 24 | ), 25 | ), 26 | )); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/usecases/details/delete_alarm_comment_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/repository/details/i_alarm_details_repository.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/usecase.dart'; 4 | 5 | final class DeleteAlarmCommentUseCase 6 | extends UseCase, DeleteCommentParams> { 7 | DeleteAlarmCommentUseCase(this.repository); 8 | 9 | final IAlarmDetailsRepository repository; 10 | 11 | @override 12 | Future call(DeleteCommentParams params) { 13 | return repository.deleteComment( 14 | params.alarmId, 15 | commentId: params.commentId, 16 | ); 17 | } 18 | } 19 | 20 | final class DeleteCommentParams { 21 | const DeleteCommentParams({required this.alarmId, required this.commentId}); 22 | 23 | final String commentId; 24 | final AlarmId alarmId; 25 | } 26 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/provision_success.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/view/states/connection_state_row.dart'; 4 | 5 | class ProvisionSuccess extends StatelessWidget { 6 | const ProvisionSuccess({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | ConnectionStateRow( 13 | S.of(context).sendingWifiCredentials, 14 | inProgress: false, 15 | ), 16 | ConnectionStateRow( 17 | S.of(context).confirmingWifiConnection, 18 | inProgress: false, 19 | ), 20 | ConnectionStateRow( 21 | S.of(context).provisionedSuccessfully, 22 | inProgress: false, 23 | ), 24 | ], 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/utils/services/layouts/i_layout_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context.dart'; 3 | import 'package:thingsboard_app/modules/main/main_navigation_item.dart'; 4 | import 'package:thingsboard_app/thingsboard_client.dart'; 5 | 6 | abstract interface class ILayoutService { 7 | List getBottomBarItems(); 8 | 9 | void setDeviceScreenSize(Size size, {required Orientation orientation}); 10 | 11 | void setBottomBarItems( 12 | List items, { 13 | required TbMainNavigationItem more, 14 | }); 15 | 16 | List getMorePageItems( 17 | TbContext tbContext, 18 | BuildContext context, 19 | ); 20 | 21 | void cachePageLayouts( 22 | List? pages, { 23 | required Authority authority, 24 | }); 25 | 26 | List getCachedPageLayouts(); 27 | } 28 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/presentation/bloc/noauth_states.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | sealed class NoAuthState extends Equatable { 4 | const NoAuthState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | final class NoAuthLoadingState extends NoAuthState { 11 | const NoAuthLoadingState(); 12 | } 13 | 14 | final class NoAuthWipState extends NoAuthState { 15 | const NoAuthWipState({required this.currentStateMessage}); 16 | 17 | final String currentStateMessage; 18 | 19 | @override 20 | List get props => [currentStateMessage]; 21 | } 22 | 23 | final class NoAuthErrorState extends NoAuthState { 24 | const NoAuthErrorState({required this.message}); 25 | 26 | final String? message; 27 | 28 | @override 29 | List get props => [message]; 30 | } 31 | 32 | final class NoAuthDoneState extends NoAuthState { 33 | const NoAuthDoneState(); 34 | } 35 | -------------------------------------------------------------------------------- /lib/core/auth/oauth2/app_secret_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/constants/app_constants.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart' show PlatformType; 3 | 4 | abstract class AppSecretProvider { 5 | 6 | factory AppSecretProvider.local() => _LocalAppSecretProvider(); 7 | Future getAppSecret(PlatformType platformType); 8 | } 9 | 10 | /// Not for production (only for debugging) 11 | class _LocalAppSecretProvider implements AppSecretProvider { 12 | @override 13 | Future getAppSecret(PlatformType platformType) async { 14 | if (platformType == PlatformType.IOS) { 15 | return ThingsboardAppConstants.thingsboardIOSAppSecret; 16 | } else if (platformType == PlatformType.ANDROID) { 17 | return ThingsboardAppConstants.thingsboardAndroidAppSecret; 18 | } 19 | 20 | throw UnsupportedError('This platform is not supported $platformType'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/utils/services/provisioning/esp_smartconfig/esp_smartconfig_service.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:esp_smartconfig/esp_smartconfig.dart'; 3 | import 'package:thingsboard_app/utils/services/provisioning/esp_smartconfig/i_esp_smartconfig_service.dart'; 4 | 5 | class EspSmartConfigService implements IEspSmartConfigService { 6 | const EspSmartConfigService(this.provisioner); 7 | 8 | final Provisioner provisioner; 9 | 10 | @override 11 | Provisioner create(SmartConfig config) { 12 | switch (config) { 13 | case SmartConfig.espTouch: 14 | return Provisioner.espTouch(); 15 | case SmartConfig.espTouchV2: 16 | return Provisioner.espTouchV2(); 17 | } 18 | } 19 | 20 | @override 21 | Future start(ProvisioningRequest request) { 22 | return provisioner.start(request); 23 | } 24 | 25 | @override 26 | Future stop() async { 27 | provisioner.stop(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/core/init/init_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 5 | import 'package:thingsboard_app/core/init/init_app.dart'; 6 | import 'package:thingsboard_app/core/init/inti_region_app.dart'; 7 | 8 | class InitRoutes extends TbRoutes { 9 | InitRoutes(super.tbContext); 10 | 11 | late final initHandler = Handler( 12 | handlerFunc: (BuildContext? context, params) { 13 | return ThingsboardInitApp(tbContext); 14 | }, 15 | ); 16 | 17 | late final regionSelectedHandler = Handler( 18 | handlerFunc: (BuildContext? context, params) { 19 | return ThingsboardInitRegionApp(tbContext); 20 | }, 21 | ); 22 | 23 | @override 24 | void doRegisterRoutes(FluroRouter router) { 25 | router.define('/', handler: regionSelectedHandler); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/mobile_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 3 | import 'package:thingsboard_app/core/logger/tb_logger.dart'; 4 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_result.dart'; 5 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_type.dart'; 6 | 7 | abstract class MobileAction { 8 | final TbLogger log = TbLogger(); 9 | WidgetMobileActionType get type; 10 | Future execute( List args, 11 | InAppWebViewController controller,); 12 | WidgetMobileActionResult handleError(Object e) { 13 | String error; 14 | if (e is PlatformException) { 15 | error = e.message ?? e.code; 16 | } else { 17 | error = e.toString(); 18 | } 19 | return WidgetMobileActionResult.errorResult(error); 20 | } 21 | } -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/activity/alarm_activity_query_ctrl.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AlarmActivityQueryCtrl extends PageKeyController { 5 | AlarmActivityQueryCtrl({ 6 | required AlarmId id, 7 | int pageSize = 20, 8 | SortOrder? sortOrder, 9 | }) : super( 10 | AlarmCommentsQuery( 11 | pageLink: PageLink( 12 | pageSize, 13 | 0, 14 | null, 15 | sortOrder ?? SortOrder('createdTime', Direction.ASC), 16 | ), 17 | id: id, 18 | ), 19 | ); 20 | 21 | @override 22 | AlarmCommentsQuery nextPageKey(AlarmCommentsQuery pageKey) { 23 | return AlarmCommentsQuery( 24 | pageLink: pageKey.pageLink.nextPageLink(), 25 | id: pageKey.id, 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/assignee/assignee_pagination_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/entities/assignee_entity.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/pagination/assignee/assignee_query_ctrl.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | import 'package:thingsboard_app/utils/services/pagination_repository.dart'; 5 | 6 | final class AssigneePaginationRepository 7 | extends PaginationRepository { 8 | AssigneePaginationRepository({ 9 | required AssigneeQueryCtrl assigneeQueryCtrl, 10 | required this.onFetchPageData, 11 | }) : super(pageKeyController: assigneeQueryCtrl); 12 | 13 | final Future> Function(PageLink) onFetchPageData; 14 | 15 | @override 16 | Future> fetchPageData(PageLink pageKey) { 17 | return onFetchPageData(pageKey); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/models/wifi_network.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'wifi_network.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _WifiNetwork _$WifiNetworkFromJson(Map json) => _WifiNetwork( 10 | ssid: json['ssid'] as String, 11 | rssi: (json['rssi'] as num).toInt(), 12 | channel: (json['channel'] as num).toInt(), 13 | auth: json['auth'] as String, 14 | password: json['password'] as String? ?? '', 15 | ); 16 | 17 | Map _$WifiNetworkToJson(_WifiNetwork instance) => 18 | { 19 | 'ssid': instance.ssid, 20 | 'rssi': instance.rssi, 21 | 'channel': instance.channel, 22 | 'auth': instance.auth, 23 | 'password': instance.password, 24 | }; 25 | -------------------------------------------------------------------------------- /lib/utils/services/endpoint/i_endpoint_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:thingsboard_app/core/auth/login/select_region/model/region.dart'; 3 | 4 | /// This service provides information about the current active endpoint. 5 | /// Since we have a feature that allows for changing endpoints, there is some 6 | /// logic associated with the active endpoint, such as dashboard loading and OAuth2A. 7 | abstract interface class IEndpointService { 8 | Future setEndpoint(String endpoint); 9 | 10 | Future getEndpoint(); 11 | 12 | Future isCustomEndpoint(); 13 | 14 | /// At times, we need to retrieve the endpoint synchronously. 15 | /// We might consider using Hive in the future. 16 | String getCachedEndpoint(); 17 | 18 | Future setRegion(Region region); 19 | 20 | Future getSelectedRegion(); 21 | 22 | ValueListenable get listenEndpointChanges; 23 | } 24 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/widgets/help_message_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 3 | 4 | class HelpTextWidget extends StatelessWidget { 5 | const HelpTextWidget(this.message, {super.key}); 6 | 7 | final String message; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | width: double.infinity, 13 | padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), 14 | decoration: BoxDecoration( 15 | color: Theme.of(context).primaryColor.withValues(alpha: .04), 16 | borderRadius: BorderRadius.circular(6), 17 | ), 18 | child: Text( 19 | message, 20 | textAlign: TextAlign.center, 21 | style: TbTextStyles.bodyMedium.copyWith( 22 | color: Colors.black.withValues(alpha: 0.54), 23 | ), 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/modules/tenant/tenants_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context_widget.dart'; 3 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 4 | 5 | import 'package:thingsboard_app/modules/tenant/tenants_list.dart'; 6 | 7 | class TenantsWidget extends TbContextWidget { 8 | TenantsWidget(super.tbContext, {super.key}); 9 | 10 | @override 11 | State createState() => _TenantsWidgetState(); 12 | } 13 | 14 | class _TenantsWidgetState extends TbContextState { 15 | final PageLinkController _pageLinkController = PageLinkController(); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return SafeArea( 20 | child: TenantsList(tbContext, _pageLinkController), 21 | ); 22 | } 23 | 24 | @override 25 | void dispose() { 26 | _pageLinkController.dispose(); 27 | super.dispose(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/presentation/widgets/endpoint_name_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 3 | 4 | class EndpointNameWidget extends StatelessWidget { 5 | const EndpointNameWidget({required this.endpoint, super.key}); 6 | 7 | final String endpoint; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | decoration: BoxDecoration( 13 | borderRadius: BorderRadius.circular(4), 14 | color: Theme.of(context).primaryColor.withValues(alpha: .06), 15 | ), 16 | padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), 17 | child: Center( 18 | child: Text( 19 | Uri.parse(endpoint).host, 20 | style: TbTextStyles.bodySmall.copyWith( 21 | color: Theme.of(context).primaryColor, 22 | ), 23 | ), 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/widget_mobile_action_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 2 | 3 | class WidgetMobileActionResult { 4 | 5 | WidgetMobileActionResult.errorResult(this.error) 6 | : hasError = true, 7 | hasResult = false; 8 | 9 | WidgetMobileActionResult.successResult(this.result) 10 | : hasError = false, 11 | hasResult = true; 12 | 13 | WidgetMobileActionResult.emptyResult() 14 | : hasError = false, 15 | hasResult = false; 16 | T? result; 17 | bool hasResult = false; 18 | String? error; 19 | bool hasError = false; 20 | 21 | Map toJson() { 22 | final json = {}; 23 | json['hasError'] = hasError; 24 | json['hasResult'] = hasResult; 25 | json['error'] = error; 26 | json['result'] = result?.toJson(); 27 | return json; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/actions/unknown_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 2 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action.dart'; 3 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 4 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_result.dart'; 5 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_type.dart'; 6 | 7 | class UnknownAction extends MobileAction { 8 | @override 9 | Future> execute( 10 | List args, InAppWebViewController controller,) async{ 11 | return WidgetMobileActionResult.errorResult( 12 | // translate-me-ignore-next-line 13 | 'Unknown actionType: ${args[0]}', 14 | ); 15 | 16 | } 17 | 18 | @override 19 | WidgetMobileActionType get type => WidgetMobileActionType.unknown; 20 | } 21 | -------------------------------------------------------------------------------- /lib/modules/alarm/data/datasource/details/i_alarm_details_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAlarmDetailsDatasource { 4 | Future> fetchAlarmComments( 5 | AlarmCommentsQuery query, 6 | ); 7 | 8 | Future acknowledgeAlarm(AlarmId id); 9 | 10 | Future clearAlarm(AlarmId id); 11 | 12 | Future postComment( 13 | AlarmId alarmId, { 14 | required String comment, 15 | }); 16 | 17 | Future updateComment( 18 | AlarmId alarmId, { 19 | required String id, 20 | required String comment, 21 | }); 22 | 23 | Future deleteComment(AlarmId id, {required String commentId}); 24 | 25 | Future> fetchAssignee(UsersAssignQuery query); 26 | 27 | Future assignAlarm(String alarmId, String assigneeId); 28 | 29 | Future unassignAlarm(String alarmId); 30 | } 31 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/repository/details/i_alarm_details_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/thingsboard_client.dart'; 2 | 3 | abstract interface class IAlarmDetailsRepository { 4 | Future> fetchAlarmComments( 5 | AlarmCommentsQuery query, 6 | ); 7 | 8 | Future acknowledgeAlarm(AlarmId id); 9 | 10 | Future clearAlarm(AlarmId id); 11 | 12 | Future postComment( 13 | AlarmId alarmId, { 14 | required String comment, 15 | }); 16 | 17 | Future updateComment( 18 | AlarmId alarmId, { 19 | required String id, 20 | required String comment, 21 | }); 22 | 23 | Future deleteComment(AlarmId id, {required String commentId}); 24 | 25 | Future> fetchAssignee(UsersAssignQuery query); 26 | 27 | Future assignAlarm(String alarmId, String assigneeId); 28 | 29 | Future unassignAlarm(String alarmId); 30 | } 31 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_details/alarm_details_events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | sealed class AlarmDetailsEvent extends Equatable { 5 | const AlarmDetailsEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class AlarmDetailsFetchEvent extends AlarmDetailsEvent { 12 | const AlarmDetailsFetchEvent({required this.id}); 13 | 14 | final String? id; 15 | 16 | @override 17 | List get props => [id]; 18 | } 19 | 20 | final class ClearAlarmEvent extends AlarmDetailsEvent { 21 | const ClearAlarmEvent(this.id); 22 | 23 | final AlarmId id; 24 | 25 | @override 26 | List get props => [id]; 27 | } 28 | 29 | final class AcknowledgeAlarmEvent extends AlarmDetailsEvent { 30 | const AcknowledgeAlarmEvent(this.id); 31 | 32 | final AlarmId id; 33 | 34 | @override 35 | List get props => [id]; 36 | } 37 | -------------------------------------------------------------------------------- /lib/utils/ui/qr_code_scanner/scan_area_clipper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScanAreaClipper extends CustomClipper { 4 | ScanAreaClipper({super.reclip, required this.areaSize}); 5 | 6 | final Size areaSize; 7 | @override 8 | Path getClip(Size size) { 9 | final Path path = Path(); 10 | 11 | // Create the outer path (full container) 12 | path.addRect(Rect.fromLTWH(0, 0, size.width, size.height)); 13 | 14 | // Create the inner path (hole) - centered 100x100 rectangle 15 | 16 | final double holeLeft = (size.width - areaSize.width) / 2; 17 | final double holeTop = (size.height - areaSize.height) / 2; 18 | 19 | final Path holePath = Path(); 20 | holePath.addRect(Rect.fromLTWH(holeLeft, holeTop, areaSize.width, areaSize.height)); 21 | 22 | return Path.combine(PathOperation.difference, path, holePath); 23 | } 24 | 25 | @override 26 | bool shouldReclip(CustomClipper oldClipper) => false; 27 | } 28 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/widgets/return_to_dashboard_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 4 | 5 | class ReturnToDashboardButton extends StatelessWidget { 6 | const ReturnToDashboardButton({required this.onTap, super.key}); 7 | 8 | final VoidCallback onTap; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return SizedBox( 13 | width: double.infinity, 14 | child: ElevatedButton( 15 | style: ElevatedButton.styleFrom( 16 | padding: const EdgeInsets.symmetric( 17 | vertical: 12, 18 | horizontal: 16, 19 | ), 20 | ), 21 | onPressed: onTap, 22 | child: Text( 23 | S.of(context).returnToDashboard, 24 | style: TbTextStyles.labelMedium.copyWith(color: Colors.white), 25 | ), 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/modules/main/main_navigation_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class TbMainNavigationItem extends Equatable { 5 | const TbMainNavigationItem({ 6 | required this.page, 7 | required this.title, 8 | required this.icon, 9 | required this.path, 10 | this.id, 11 | this.showAdditionalIcon = false, 12 | this.additionalIconSmall, 13 | this.additionalIconLarge, 14 | }); 15 | 16 | final Widget page; 17 | final String title; 18 | final IconData icon; 19 | final String path; 20 | final String? id; 21 | final bool showAdditionalIcon; 22 | final Widget? additionalIconSmall; 23 | final Widget? additionalIconLarge; 24 | 25 | @override 26 | List get props => [ 27 | page, 28 | title, 29 | icon, 30 | path, 31 | id, 32 | showAdditionalIcon, 33 | additionalIconSmall, 34 | additionalIconLarge, 35 | ]; 36 | } 37 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | jcenter() 5 | mavenCentral() 6 | maven { url ("https://jitpack.io/") } 7 | } 8 | } 9 | 10 | rootProject.buildDir = '../build' 11 | subprojects { 12 | project.buildDir = "${rootProject.buildDir}/${project.name}" 13 | } 14 | subprojects { 15 | afterEvaluate { project -> 16 | if (project.plugins.hasPlugin("com.android.application") || 17 | project.plugins.hasPlugin("com.android.library")) { 18 | project.android { 19 | compileSdkVersion 35 20 | buildToolsVersion "35.0.0" 21 | if (namespace == null) { 22 | namespace project.group 23 | } 24 | } 25 | } 26 | 27 | } 28 | } 29 | subprojects { 30 | project.evaluationDependsOn(':app') 31 | } 32 | 33 | tasks.register("clean", Delete) { 34 | delete rootProject.buildDir 35 | } 36 | -------------------------------------------------------------------------------- /assets/images/scaner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/assignee/assignee_query_ctrl.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AssigneeQueryCtrl extends PageKeyController { 5 | AssigneeQueryCtrl({ 6 | int pageSize = 50, 7 | String? searchText, 8 | SortOrder? sortOrder, 9 | }) : super( 10 | PageLink( 11 | pageSize, 12 | 0, 13 | searchText, 14 | sortOrder ?? 15 | SortOrder( 16 | 'email', 17 | Direction.ASC, 18 | ), 19 | ), 20 | ); 21 | 22 | @override 23 | PageLink nextPageKey(PageLink pageKey) { 24 | return pageKey.nextPageLink(); 25 | } 26 | 27 | void onSearchText(String? searchText) { 28 | final query = value.pageKey; 29 | query.page = 0; 30 | query.textSearch = searchText; 31 | 32 | notifyListeners(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/filters/filters/alarm_assignee_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/logger/tb_logger.dart'; 2 | import 'package:thingsboard_app/modules/alarm/presentation/bloc/filters/filters/i_alarm_filter.dart'; 3 | 4 | class AlarmAssigneeFilter implements IAlarmFilter { 5 | AlarmAssigneeFilter({required this.logger, T? initiallySelected}) { 6 | selectedUsed = initiallySelected; 7 | } 8 | 9 | T? selectedUsed; 10 | final TbLogger logger; 11 | 12 | @override 13 | T? getSelectedFilterData() { 14 | logger.debug( 15 | 'AlarmAssigneeFilter::getSelectedFilterData() -> $selectedUsed', 16 | ); 17 | 18 | return selectedUsed; 19 | } 20 | 21 | @override 22 | void updateSelectedData(dynamic data) { 23 | logger.debug( 24 | 'AlarmAssigneeFilter::updateSelectedData($data)', 25 | ); 26 | 27 | selectedUsed = data as T; 28 | } 29 | 30 | @override 31 | void reset() { 32 | selectedUsed = null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.3.2" apply false 22 | // START: FlutterFire Configuration 23 | // id "com.google.gms.google-services" version "4.3.14" apply false 24 | // END: FlutterFire Configuration 25 | id "org.jetbrains.kotlin.android" version "2.0.20" apply false 26 | } 27 | 28 | include ":app" -------------------------------------------------------------------------------- /lib/core/auth/login/di/login_di.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/auth/oauth2/app_secret_provider.dart'; 2 | import 'package:thingsboard_app/core/auth/oauth2/i_oauth2_client.dart'; 3 | import 'package:thingsboard_app/core/auth/oauth2/tb_oauth2_client.dart'; 4 | import 'package:thingsboard_app/locator.dart'; 5 | 6 | abstract final class LoginDi { 7 | static const scopeName = 'LoginDi'; 8 | static void init() { 9 | if (getIt.hasScope(scopeName)) { 10 | return; 11 | } 12 | getIt.pushNewScope( 13 | scopeName: scopeName, 14 | init: (locator) { 15 | locator.registerFactory( 16 | () => TbOAuth2Client( 17 | tbLogger: locator(), 18 | deviceInfoService: locator(), 19 | appSecretProvider: AppSecretProvider.local(),), 20 | ); 21 | },); 22 | } 23 | 24 | static void dispose() { 25 | if(getIt.hasScope(scopeName)) { 26 | getIt.dropScope(scopeName); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/assignee/alarm_assignee_pagiation_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/modules/alarm/domain/entities/assignee_entity.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/pagination/assignee/alarm_assignee_query_ctrl.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | import 'package:thingsboard_app/utils/services/pagination_repository.dart'; 5 | 6 | final class AlarmAssigneePaginationRepository 7 | extends PaginationRepository { 8 | AlarmAssigneePaginationRepository({ 9 | required AlarmAssigneeQueryCtrl assigneeQueryCtrl, 10 | required this.onFetchPageData, 11 | }) : super(pageKeyController: assigneeQueryCtrl); 12 | 13 | final Future> Function(UsersAssignQuery) 14 | onFetchPageData; 15 | 16 | @override 17 | Future> fetchPageData( 18 | UsersAssignQuery pageKey, 19 | ) { 20 | return onFetchPageData(pageKey); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/auth/login/bloc/auth_states.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:recaptcha_enterprise_flutter/recaptcha_client.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart' 4 | show MobileSelfRegistrationParams, OAuth2ClientInfo; 5 | 6 | sealed class AuthState extends Equatable { 7 | const AuthState(); 8 | 9 | @override 10 | List get props => []; 11 | } 12 | 13 | final class AuthLoadingState extends AuthState { 14 | const AuthLoadingState(); 15 | } 16 | 17 | final class AuthDataState extends AuthState { 18 | const AuthDataState({ 19 | required this.oAuthClients, 20 | required this.selfRegistrationParams, 21 | required this.recaptchaClient, 22 | }); 23 | 24 | final List oAuthClients; 25 | final MobileSelfRegistrationParams? selfRegistrationParams; 26 | final RecaptchaClient? recaptchaClient; 27 | 28 | @override 29 | List get props => 30 | [oAuthClients, selfRegistrationParams, recaptchaClient]; 31 | } 32 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/claiming_wip.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/view/states/connection_state_row.dart'; 4 | 5 | class ClaimingWip extends StatelessWidget { 6 | const ClaimingWip({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | ConnectionStateRow( 13 | S.of(context).sendingWifiCredentials, 14 | inProgress: false, 15 | ), 16 | ConnectionStateRow( 17 | S.of(context).confirmingWifiConnection, 18 | inProgress: false, 19 | ), 20 | ConnectionStateRow( 21 | S.of(context).provisionedSuccessfully, 22 | inProgress: false, 23 | ), 24 | ConnectionStateRow( 25 | S.of(context).claimingDevice, 26 | inProgress: true, 27 | ), 28 | ], 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/bloc/device_provisioning_events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | sealed class DeviceProvisioningEvent extends Equatable { 4 | const DeviceProvisioningEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | final class SendWifiCredentialsEvent extends DeviceProvisioningEvent { 11 | const SendWifiCredentialsEvent(); 12 | } 13 | 14 | final class ConfirmConnectionEvent extends DeviceProvisioningEvent { 15 | const ConfirmConnectionEvent(); 16 | } 17 | 18 | final class SuccessfullyProvisionedEvent extends DeviceProvisioningEvent { 19 | const SuccessfullyProvisionedEvent(); 20 | } 21 | 22 | final class ErrorDuringProvisioningEvent extends DeviceProvisioningEvent { 23 | const ErrorDuringProvisioningEvent(); 24 | } 25 | 26 | final class ProvisioningIdleEvent extends DeviceProvisioningEvent { 27 | const ProvisioningIdleEvent(); 28 | } 29 | 30 | final class ProceedWithClaimingEvent extends DeviceProvisioningEvent { 31 | const ProceedWithClaimingEvent(); 32 | } 33 | -------------------------------------------------------------------------------- /lib/app_bloc_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc/flutter_bloc.dart'; 2 | import 'package:thingsboard_app/core/logger/tb_logger.dart'; 3 | 4 | class AppBlocObserver extends BlocObserver { 5 | const AppBlocObserver(this.logger); 6 | 7 | final TbLogger logger; 8 | 9 | @override 10 | void onCreate(BlocBase bloc) { 11 | super.onCreate(bloc); 12 | logger.info('AppBlocObserver::onCreate(${bloc.runtimeType})'); 13 | } 14 | 15 | @override 16 | void onEvent(Bloc bloc, Object? event) { 17 | super.onEvent(bloc, event); 18 | logger.info('AppBlocObserver::onEvent(${bloc.runtimeType}, $event)'); 19 | } 20 | 21 | @override 22 | void onError(BlocBase bloc, Object error, StackTrace stackTrace) { 23 | super.onError(bloc, error, stackTrace); 24 | logger.info( 25 | 'AppBlocObserver::onError(${bloc.runtimeType}, $error, $stackTrace)', 26 | ); 27 | } 28 | 29 | @override 30 | void onClose(BlocBase bloc) { 31 | super.onClose(bloc); 32 | logger.info('AppBlocObserver::onClose(${bloc.runtimeType})'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/claiming_error.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/view/states/connection_state_row.dart'; 4 | 5 | class ClaimingError extends StatelessWidget { 6 | const ClaimingError({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | ConnectionStateRow( 13 | S.of(context).sendingWifiCredentials, 14 | inProgress: false, 15 | ), 16 | ConnectionStateRow( 17 | S.of(context).confirmingWifiConnection, 18 | inProgress: false, 19 | ), 20 | ConnectionStateRow( 21 | S.of(context).provisionedSuccessfully, 22 | inProgress: false, 23 | ), 24 | ConnectionStateRow( 25 | S.of(context).claimingDevice, 26 | inProgress: false, 27 | error: true, 28 | ), 29 | ], 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/modules/tenant/tenant_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 4 | 5 | import 'package:thingsboard_app/modules/tenant/tenant_details_page.dart'; 6 | import 'package:thingsboard_app/modules/tenant/tenants_page.dart'; 7 | 8 | class TenantRoutes extends TbRoutes { 9 | TenantRoutes(super.tbContext); 10 | late Handler tenantsHandler = Handler( 11 | handlerFunc: (BuildContext? context, params) { 12 | final searchMode = params['search']?.first == 'true'; 13 | return TenantsPage(tbContext, searchMode: searchMode); 14 | }, 15 | ); 16 | 17 | late Handler tenantDetailsHandler = Handler( 18 | handlerFunc: (BuildContext? context, params) { 19 | return TenantDetailsPage(tbContext, params['id']!.first); 20 | }, 21 | ); 22 | 23 | @override 24 | void doRegisterRoutes(FluroRouter router) { 25 | router.define('/tenants', handler: tenantsHandler); 26 | router.define('/tenant/:id', handler: tenantDetailsHandler); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_details/alarm_details_states.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | sealed class AlarmDetailsState extends Equatable { 5 | const AlarmDetailsState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class AlarmDetailsLoadingState extends AlarmDetailsState { 12 | const AlarmDetailsLoadingState(); 13 | } 14 | 15 | final class AlarmDetailsLoadedState extends AlarmDetailsState { 16 | const AlarmDetailsLoadedState( 17 | this.alarmInfo, { 18 | required this.acknowledge, 19 | required this.clear, 20 | }); 21 | 22 | final AlarmInfo alarmInfo; 23 | final bool acknowledge; 24 | final bool clear; 25 | 26 | @override 27 | List get props => [alarmInfo, acknowledge, clear]; 28 | } 29 | 30 | final class AlarmDetailsErrorState extends AlarmDetailsState { 31 | const AlarmDetailsErrorState(this.message); 32 | 33 | final String message; 34 | 35 | @override 36 | List get props => [message]; 37 | } 38 | -------------------------------------------------------------------------------- /lib/widgets/two_value_listenable_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class TwoValueListenableBuilder extends StatelessWidget { 5 | const TwoValueListenableBuilder({ 6 | required this.firstValueListenable, 7 | required this.secondValueListenable, 8 | required this.builder, 9 | this.child, 10 | super.key, 11 | }); 12 | 13 | final ValueListenable firstValueListenable; 14 | final ValueListenable secondValueListenable; 15 | final Widget? child; 16 | final Widget Function(BuildContext context, A a, B b, Widget? child) builder; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return ValueListenableBuilder( 21 | valueListenable: firstValueListenable, 22 | builder: (_, a, _) { 23 | return ValueListenableBuilder( 24 | valueListenable: secondValueListenable, 25 | builder: (context, b, _) { 26 | return builder(context, a, b, child); 27 | }, 28 | ); 29 | }, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/modules/main/main_item_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context_widget.dart'; 3 | import 'package:thingsboard_app/generated/l10n.dart'; 4 | 5 | class MainItemWidget extends TbContextWidget { 6 | MainItemWidget( 7 | super.tbContext, { 8 | required this.child, 9 | required this.path, 10 | super.key, 11 | }); 12 | 13 | final Widget? child; 14 | final String path; 15 | 16 | @override 17 | State createState() => _MainItemWidgetState(); 18 | } 19 | 20 | class _MainItemWidgetState extends TbContextState 21 | with AutomaticKeepAliveClientMixin { 22 | @override 23 | Widget build(BuildContext context) { 24 | super.build(context); 25 | return widget.child ?? 26 | Scaffold( 27 | appBar: AppBar(title: Text(S.of(context).notFound)), 28 | body: Center( 29 | child: Text(S.of(context).routeNotDefined(widget.path)), 30 | ), 31 | ); 32 | } 33 | 34 | @override 35 | bool get wantKeepAlive => true; 36 | } 37 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarm_types/alarm_types_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | sealed class AlarmTypesEvent extends Equatable { 4 | const AlarmTypesEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | final class AlarmTypesSelectedEvent extends AlarmTypesEvent { 11 | const AlarmTypesSelectedEvent({required this.type}); 12 | 13 | final String type; 14 | 15 | @override 16 | List get props => [type]; 17 | } 18 | 19 | final class AlarmTypesRemoveSelectedEvent extends AlarmTypesEvent { 20 | const AlarmTypesRemoveSelectedEvent({required this.type}); 21 | 22 | final String type; 23 | 24 | @override 25 | List get props => [type]; 26 | } 27 | 28 | final class AlarmTypesResetEvent extends AlarmTypesEvent { 29 | const AlarmTypesResetEvent(); 30 | } 31 | 32 | final class AlarmTypesRefreshEvent extends AlarmTypesEvent { 33 | const AlarmTypesRefreshEvent(); 34 | } 35 | 36 | final class AlarmTypesResetUnCommittedChanges extends AlarmTypesEvent { 37 | const AlarmTypesResetUnCommittedChanges(); 38 | } 39 | -------------------------------------------------------------------------------- /lib/modules/asset/asset_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 4 | import 'package:thingsboard_app/modules/asset/asset_details_page.dart'; 5 | import 'package:thingsboard_app/modules/asset/assets_page.dart'; 6 | class AssetRoutes extends TbRoutes { 7 | AssetRoutes(super.tbContext); 8 | late final assetsHandler = Handler( 9 | handlerFunc: ( context, params) { 10 | final searchParams = params['search'] as List?; 11 | final searchMode = searchParams?.firstOrNull == 'true'; 12 | return AssetsPage(tbContext, searchMode: searchMode); 13 | }, 14 | ); 15 | 16 | late Handler assetDetailsHandler = Handler( 17 | handlerFunc: (BuildContext? context, params) { 18 | 19 | return AssetDetailsPage(tbContext, params['id']!.first); 20 | }, 21 | ); 22 | 23 | @override 24 | void doRegisterRoutes(FluroRouter router) { 25 | router.define('/assets', handler: assetsHandler); 26 | router.define('/asset/:id', handler: assetDetailsHandler); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/modules/customer/customer_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 4 | 5 | import 'package:thingsboard_app/modules/customer/customer_details_page.dart'; 6 | import 'package:thingsboard_app/modules/customer/customers_page.dart'; 7 | 8 | class CustomerRoutes extends TbRoutes { 9 | CustomerRoutes(super.tbContext); 10 | late final customersHandler = Handler( 11 | handlerFunc: (BuildContext? context, params) { 12 | final searchMode = params['search']?.first == 'true'; 13 | return CustomersPage(tbContext, searchMode: searchMode); 14 | }, 15 | ); 16 | 17 | late final customerDetailsHandler = Handler( 18 | handlerFunc: (BuildContext? context, params) { 19 | return CustomerDetailsPage(tbContext, params['id']!.first); 20 | }, 21 | ); 22 | 23 | @override 24 | void doRegisterRoutes(FluroRouter router) { 25 | router.define('/customers', handler: customersHandler); 26 | router.define('/customer/:id', handler: customerDetailsHandler); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/utils/services/overlay_service/i_overlay_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/translation_utils.dart'; 2 | 3 | abstract interface class IOverlayService { 4 | void hideNotification(); 5 | 6 | Future showAlertDialog({ 7 | required TranslatedDialogBuilder content 8 | }); 9 | Future showConfirmDialog({ 10 | required TranslatedDialogBuilder content 11 | }); 12 | void showErrorNotification( 13 | TranslationBuilder tranlatedMessage, { 14 | Duration? duration, 15 | }); 16 | void showInfoNotification(TranslationBuilder message, {Duration? duration}); 17 | void showWarnNotification(TranslationBuilder message, {Duration? duration}); 18 | void showSuccessNotification( 19 | TranslationBuilder message, { 20 | Duration? duration, 21 | }); 22 | } 23 | 24 | 25 | class DialogContent { 26 | DialogContent({ 27 | required this.title, 28 | required this.message, 29 | required this.ok, 30 | this.cancel, 31 | }); 32 | final String title; 33 | final String message; 34 | final String ok; 35 | final String? cancel; 36 | } 37 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/entities/assignee_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/core/usecases/user_details_usecase.dart'; 3 | import 'package:thingsboard_app/thingsboard_client.dart'; 4 | 5 | class AssigneeEntity extends Equatable { 6 | const AssigneeEntity({ 7 | required this.userInfo, 8 | required this.shortName, 9 | required this.displayName, 10 | }); 11 | 12 | factory AssigneeEntity.fromUserInfo( 13 | UserInfo info, { 14 | required UserDetailsUseCase detailsUseCase, 15 | }) { 16 | final details = detailsUseCase( 17 | UserDetailsParams( 18 | firstName: info.firstName, 19 | lastName: info.lastName, 20 | email: info.email, 21 | ), 22 | ); 23 | 24 | return AssigneeEntity( 25 | userInfo: info, 26 | displayName: details.displayName, 27 | shortName: details.shortName, 28 | ); 29 | } 30 | 31 | final UserInfo userInfo; 32 | final String shortName; 33 | final String displayName; 34 | 35 | @override 36 | List get props => [userInfo, shortName, displayName]; 37 | } 38 | -------------------------------------------------------------------------------- /lib/utils/ui/tb_alert_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 3 | 4 | class TbAlertDialog extends StatelessWidget { 5 | const TbAlertDialog({ 6 | required this.title, 7 | required this.content, 8 | required this.actions, 9 | super.key, 10 | }); 11 | 12 | final Widget title; 13 | final Widget content; 14 | final List actions; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return AlertDialog( 19 | title: title, 20 | titleTextStyle: TbTextStyles.titleXs.copyWith( 21 | color: const Color(0xff1D1B20), 22 | ), 23 | titlePadding: const EdgeInsets.all(24), 24 | contentPadding: const EdgeInsets.only(bottom: 24, left: 24, right: 24), 25 | content: content, 26 | contentTextStyle: TbTextStyles.bodyMedium.copyWith( 27 | color: const Color(0xff49454F), 28 | ), 29 | actions: actions, 30 | shape: const RoundedRectangleBorder( 31 | borderRadius: BorderRadius.all(Radius.circular(8)), 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/alarms_events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/modules/alarm/domain/entities/alarm_filters_entity.dart'; 3 | 4 | sealed class AlarmEvent extends Equatable { 5 | const AlarmEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class AlarmFiltersResetEvent extends AlarmEvent { 12 | const AlarmFiltersResetEvent(); 13 | } 14 | 15 | final class AlarmFiltersUpdateEvent extends AlarmEvent { 16 | const AlarmFiltersUpdateEvent({required this.filtersEntity}); 17 | 18 | final AlarmFiltersEntity filtersEntity; 19 | 20 | @override 21 | List get props => [filtersEntity]; 22 | } 23 | 24 | final class AlarmSearchTextChanged extends AlarmEvent { 25 | const AlarmSearchTextChanged({required this.searchText}); 26 | 27 | final String? searchText; 28 | 29 | @override 30 | List get props => [searchText]; 31 | } 32 | 33 | final class AlarmsRefreshPageEvent extends AlarmEvent { 34 | const AlarmsRefreshPageEvent(); 35 | 36 | @override 37 | List get props => [double.nan]; 38 | } 39 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/filters/filters/alarm_type_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/logger/tb_logger.dart'; 2 | import 'package:thingsboard_app/modules/alarm/presentation/bloc/filters/filters/i_alarm_filter.dart'; 3 | 4 | class AlarmTypeFilter implements IAlarmFilter { 5 | AlarmTypeFilter({required this.logger, T? initiallySelected}) { 6 | if (initiallySelected != null) { 7 | alarmTypeSelected.add(initiallySelected); 8 | } 9 | } 10 | 11 | final alarmTypeSelected = {}; 12 | final TbLogger logger; 13 | 14 | @override 15 | Set getSelectedFilterData() { 16 | logger.debug( 17 | 'AlarmTypeFilter::getSelectedFilterData() -> $alarmTypeSelected', 18 | ); 19 | 20 | return Set.of(alarmTypeSelected); 21 | } 22 | 23 | @override 24 | void updateSelectedData(dynamic data) { 25 | logger.debug( 26 | 'AlarmTypeFilter::updateSelectedData($data)', 27 | ); 28 | 29 | alarmTypeSelected 30 | ..clear() 31 | ..addAll(data as Set); 32 | } 33 | 34 | @override 35 | void reset() { 36 | alarmTypeSelected.clear(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/modules/notification/usecase/handle_notification_tap_usecase.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: unused_import 2 | 3 | import 'package:thingsboard_app/core/context/tb_context.dart'; 4 | import 'package:thingsboard_app/modules/notification/usecase/handle_notification_tap_params.dart'; 5 | import 'package:thingsboard_app/thingsboard_client.dart'; 6 | import 'package:thingsboard_app/utils/services/notification_service.dart'; 7 | import 'package:thingsboard_app/utils/usecase.dart'; 8 | 9 | class HandleNotificationTapUsecase extends UseCase { 10 | @override 11 | void call(HandleNotificationTapParams params) { 12 | final data = params.notification.additionalConfig?['onClick'] 13 | as Map? ?? 14 | {}; 15 | final stateEntityId = params.notification.info?.stateEntityId; 16 | data['stateEntityId'] = stateEntityId?.id; 17 | data['stateEntityType'] = stateEntityId?.entityType.name; 18 | return NotificationService.handleClickOnNotification( 19 | data, 20 | params.tbContext, 21 | isOnNotificationsScreenAlready: true, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/modules/device/devices_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/core/context/tb_context_widget.dart'; 3 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 4 | import 'package:thingsboard_app/modules/device/device_profiles_grid.dart'; 5 | import 'package:thingsboard_app/widgets/tb_app_bar.dart'; 6 | 7 | class DevicesPage extends TbPageWidget { 8 | DevicesPage(super.tbContext, {super.key}); 9 | 10 | @override 11 | State createState() => _DevicesPageState(); 12 | } 13 | 14 | class _DevicesPageState extends TbPageState { 15 | final PageLinkController _pageLinkController = PageLinkController(pageSize: 10); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | final deviceProfilesList = DeviceProfilesGrid(tbContext, _pageLinkController); 20 | return Scaffold( 21 | appBar: TbAppBar(tbContext, title: Text(deviceProfilesList.title)), 22 | body: deviceProfilesList, 23 | ); 24 | } 25 | 26 | @override 27 | void dispose() { 28 | _pageLinkController.dispose(); 29 | super.dispose(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/actions/show_map_location_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/utils/services/mobile_actions/actions/url_action.dart'; 2 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_type.dart'; 3 | 4 | class ShowMapLocationAction extends UrlAction { 5 | @override 6 | WidgetMobileActionType get type => WidgetMobileActionType.mapLocation; 7 | @override 8 | Future getUrl(List args) => getMapUrl(args, false); 9 | Future getMapUrl( 10 | List args, 11 | bool directionElseLocation, 12 | ) async { 13 | try { 14 | num? lat; 15 | num? lon; 16 | if (args.length > 2 && args[1] is num && args[2] is num) { 17 | lat = num.parse(args[1].toString()); 18 | lon = num.parse(args[2].toString()); 19 | } else { 20 | return ''; 21 | } 22 | var url = 'https://www.google.com/maps/'; 23 | return url += directionElseLocation 24 | ? 'dir/?api=1&destination=$lat,$lon' 25 | : 'search/?api=1&query=$lat,$lon'; 26 | } catch (e) { 27 | return ''; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/widgets/dotted_point_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 3 | 4 | class DottedPointWidget extends StatelessWidget { 5 | const DottedPointWidget(this.text, {super.key}); 6 | 7 | final String text; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Row( 12 | children: [ 13 | Container( 14 | padding: const EdgeInsets.all(3), 15 | alignment: Alignment.center, 16 | decoration: BoxDecoration( 17 | color: Colors.black, 18 | shape: BoxShape.circle, 19 | border: Border.all(color: Colors.black.withValues(alpha: .54)), 20 | ), 21 | ), 22 | const SizedBox(width: 16), 23 | Padding( 24 | padding: const EdgeInsets.only(bottom: 3), 25 | child: Text( 26 | text, 27 | style: TbTextStyles.bodyMedium.copyWith( 28 | color: Colors.black.withValues(alpha: .54), 29 | ), 30 | ), 31 | ), 32 | ], 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | 11 | self.registerTbWebAuth() 12 | 13 | if #available(iOS 10.0, *) { 14 | UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate 15 | } 16 | 17 | GeneratedPluginRegistrant.register(with: self) 18 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 19 | } 20 | 21 | private func registerTbWebAuth() { 22 | let controller : FlutterViewController = window?.rootViewController as! FlutterViewController 23 | let channel = FlutterMethodChannel(name: "tb_web_auth", binaryMessenger: controller.binaryMessenger) 24 | let instance = TbWebAuthHandler() 25 | channel.setMethodCallHandler({ 26 | (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in 27 | instance.handle(call, result: result) 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/widgets/assignee/user_info_avatar_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | class UserInfoAvatarWidget extends StatelessWidget { 5 | const UserInfoAvatarWidget({ 6 | required this.shortName, 7 | required this.color, 8 | super.key, 9 | }) : assert(shortName.length <= 2, 'shortName is $shortName'); 10 | 11 | final String shortName; 12 | final Color color; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | decoration: BoxDecoration( 18 | borderRadius: BorderRadius.circular(100), 19 | color: color, 20 | ), 21 | padding: const EdgeInsets.all(4), 22 | height: 32, 23 | width: 32, 24 | child: Center( 25 | child: Text( 26 | shortName, 27 | style: GoogleFonts.roboto( 28 | fontWeight: FontWeight.w700, 29 | fontSize: 14, 30 | letterSpacing: 1, 31 | height: 1.14, 32 | color: Colors.white, 33 | ), 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/widgets/try_again_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 4 | 5 | class TryAgainButton extends StatelessWidget { 6 | const TryAgainButton({required this.onTryAgain, this.label, super.key}); 7 | 8 | final String? label; 9 | final VoidCallback onTryAgain; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return InkWell( 14 | onTap: onTryAgain, 15 | child: Container( 16 | width: double.infinity, 17 | padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), 18 | decoration: BoxDecoration( 19 | border: Border.all(color: Colors.black.withValues(alpha: .12)), 20 | borderRadius: BorderRadius.circular(4), 21 | ), 22 | alignment: Alignment.center, 23 | child: Text( 24 | label ?? S.of(context).tryAgain, 25 | style: TbTextStyles.labelMedium.copyWith( 26 | color: Theme.of(context).primaryColor, 27 | ), 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | android/build/ 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | ios/Flutter/AppConfig.xcconfig 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | /ios/build/ 34 | 35 | .vscode/ 36 | # Web related 37 | lib/generated_plugin_registrant.dart 38 | 39 | # Symbolication related 40 | app.*.symbols 41 | 42 | # Obfuscation related 43 | app.*.map.json 44 | app_constants.json 45 | google-services.json 46 | GoogleService-Info.plist 47 | # Android Studio will place build artifacts here 48 | /android/app/debug 49 | /android/app/profile 50 | /android/app/release 51 | /android/app/.cxx 52 | # FVM Version Cache 53 | .fvm/ 54 | tb_firebase_options.dart 55 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/routes/noauth_routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:thingsboard_app/config/routes/tb_routes.dart'; 3 | import 'package:thingsboard_app/core/auth/noauth/data/model/switch_endpoint_args.dart'; 4 | import 'package:thingsboard_app/core/auth/noauth/presentation/view/switch_endpoint_noauth_view.dart'; 5 | 6 | class NoAuthRoutes extends TbRoutes { 7 | NoAuthRoutes(super.tbContext); 8 | 9 | static const noAuthPageRoutes = '/api/noauth/qr'; 10 | 11 | late final noAuthQrHandler = Handler( 12 | handlerFunc: (context, params) { 13 | final rawArgs = context?.settings?.arguments as Map?; 14 | if((rawArgs != null && rawArgs['secret'] == null) || rawArgs == null) { 15 | return SwitchEndpointNoAuthView( 16 | tbContext, 17 | arguments: null, 18 | ); 19 | } 20 | return SwitchEndpointNoAuthView( 21 | tbContext, 22 | arguments: SwitchEndpointArgs.fromJson(rawArgs), 23 | ); 24 | }, 25 | ); 26 | 27 | @override 28 | void doRegisterRoutes(FluroRouter router) { 29 | router.define(noAuthPageRoutes, handler: noAuthQrHandler); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/modules/alarm/domain/pagination/assignee/alarm_assignee_query_ctrl.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/entity/entities_base.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | 4 | class AlarmAssigneeQueryCtrl extends PageKeyController { 5 | AlarmAssigneeQueryCtrl({ 6 | required AlarmId id, 7 | int pageSize = 50, 8 | String? searchText, 9 | SortOrder? sortOrder, 10 | }) : super( 11 | UsersAssignQuery( 12 | pageLink: PageLink( 13 | pageSize, 14 | 0, 15 | searchText, 16 | sortOrder ?? SortOrder('email', Direction.ASC), 17 | ), 18 | id: id, 19 | ), 20 | ); 21 | 22 | @override 23 | UsersAssignQuery nextPageKey(UsersAssignQuery pageKey) { 24 | return UsersAssignQuery( 25 | pageLink: pageKey.pageLink.nextPageLink(), 26 | id: pageKey.id, 27 | ); 28 | } 29 | 30 | void onSearchText(String? searchText) { 31 | final query = value.pageKey; 32 | query.pageLink.page = 0; 33 | query.pageLink.textSearch = searchText; 34 | 35 | notifyListeners(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/bloc/filters/filters/alarm_severity_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_app/core/logger/tb_logger.dart'; 2 | import 'package:thingsboard_app/modules/alarm/presentation/bloc/filters/filters/i_alarm_filter.dart'; 3 | 4 | class AlarmSeverityFilter implements IAlarmFilter { 5 | AlarmSeverityFilter({required this.logger, T? initiallySelected}) { 6 | if (initiallySelected != null) { 7 | alarmSeveritySelected.add(initiallySelected); 8 | } 9 | } 10 | 11 | final alarmSeveritySelected = {}; 12 | final TbLogger logger; 13 | 14 | @override 15 | Set getSelectedFilterData() { 16 | logger.debug( 17 | 'AlarmSeverityFilter::getSelectedFilterData() -> $alarmSeveritySelected', 18 | ); 19 | 20 | return Set.of(alarmSeveritySelected); 21 | } 22 | 23 | @override 24 | void updateSelectedData(dynamic data) { 25 | logger.debug( 26 | 'AlarmStatusFilter::updateSelectedData($data)', 27 | ); 28 | 29 | alarmSeveritySelected 30 | ..clear() 31 | ..addAll(data as Set); 32 | } 33 | 34 | @override 35 | void reset() { 36 | alarmSeveritySelected.clear(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/ble/bloc/events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | sealed class EspBleProvisioningEvent extends Equatable { 4 | const EspBleProvisioningEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | final class EspBleScanNetworksEvent extends EspBleProvisioningEvent { 11 | const EspBleScanNetworksEvent({ 12 | required this.deviceName, 13 | required this.pop, 14 | }); 15 | 16 | final String deviceName; 17 | final String pop; // proofOfPossession 18 | 19 | @override 20 | List get props => [pop, deviceName]; 21 | } 22 | 23 | final class EspBleProvisionDeviceEvent extends EspBleProvisioningEvent { 24 | const EspBleProvisionDeviceEvent({ 25 | required this.device, 26 | required this.pop, 27 | required this.ssid, 28 | required this.pass, 29 | }); 30 | 31 | final String device; 32 | final String pop; 33 | final String ssid; 34 | final String pass; 35 | 36 | @override 37 | List get props => [device, pop, ssid, pass]; 38 | } 39 | 40 | final class EspBleProvisioningDoneEvent extends EspBleProvisioningEvent { 41 | const EspBleProvisioningDoneEvent(); 42 | } 43 | -------------------------------------------------------------------------------- /lib/utils/services/mobile_actions/actions/url_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 2 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action.dart'; 3 | import 'package:thingsboard_app/utils/services/mobile_actions/mobile_action_result.dart'; 4 | import 'package:thingsboard_app/utils/services/mobile_actions/results/launch_result.dart'; 5 | import 'package:thingsboard_app/utils/services/mobile_actions/widget_mobile_action_result.dart'; 6 | import 'package:url_launcher/url_launcher_string.dart'; 7 | 8 | abstract class UrlAction extends MobileAction { 9 | Future getUrl(List args); 10 | @override 11 | Future> execute( 12 | List args, InAppWebViewController controller,) async { 13 | final urlToLaunch = await getUrl(args); 14 | 15 | return WidgetMobileActionResult.successResult(await tryLaunch(urlToLaunch)); 16 | } 17 | 18 | static Future tryLaunch( 19 | String url, 20 | ) async { 21 | 22 | if (await canLaunchUrlString(url)) { 23 | await launchUrlString(url); 24 | return LaunchResult(true); 25 | } 26 | return LaunchResult(false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/modules/device/provisioning/view/states/manually_reconnect_to_wifi.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/generated/l10n.dart'; 3 | import 'package:thingsboard_app/modules/device/provisioning/widgets/dotted_point_widget.dart'; 4 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 5 | 6 | class ManuallyReconnectToWifi extends StatelessWidget { 7 | const ManuallyReconnectToWifi({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Column( 12 | children: [ 13 | Text( 14 | S.of(context).pleaseFollowTheNextStepsToReconnectnyourPhoneToYour, 15 | textAlign: TextAlign.center, 16 | style: TbTextStyles.bodyMedium.copyWith( 17 | color: Colors.black.withValues(alpha: .54), 18 | ), 19 | ), 20 | const SizedBox(height: 16), 21 | DottedPointWidget(S.of(context).openWifiSettings), 22 | const SizedBox(height: 16), 23 | DottedPointWidget(S.of(context).connectToTheWifiYouUsuallyUse), 24 | const SizedBox(height: 16), 25 | DottedPointWidget(S.of(context).returnToTheAppAndTapReadyButton), 26 | ], 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/core/auth/noauth/presentation/bloc/noauth_events.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:thingsboard_app/core/auth/noauth/data/model/switch_endpoint_args.dart'; 3 | 4 | sealed class NoAuthEvent extends Equatable { 5 | const NoAuthEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class SwitchToAnotherEndpointEvent extends NoAuthEvent { 12 | const SwitchToAnotherEndpointEvent({required this.parameters}); 13 | 14 | final SwitchEndpointArgs? parameters; 15 | 16 | @override 17 | List get props => [parameters]; 18 | } 19 | 20 | final class SwitchEndpointProgressUpdateEvent extends NoAuthEvent { 21 | const SwitchEndpointProgressUpdateEvent({required this.progressMessage}); 22 | 23 | final String progressMessage; 24 | 25 | @override 26 | List get props => [progressMessage]; 27 | } 28 | 29 | final class SwitchEndpointDoneEvent extends NoAuthEvent { 30 | const SwitchEndpointDoneEvent(); 31 | } 32 | 33 | final class SwitchEndpointErrorEvent extends NoAuthEvent { 34 | const SwitchEndpointErrorEvent({required this.message}); 35 | 36 | final String? message; 37 | 38 | @override 39 | List get props => [message]; 40 | } 41 | -------------------------------------------------------------------------------- /lib/modules/alarm/presentation/widgets/activity/system_activity_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:thingsboard_app/thingsboard_client.dart'; 3 | import 'package:thingsboard_app/utils/ui/tb_text_styles.dart'; 4 | import 'package:timeago/timeago.dart' as timeago; 5 | 6 | class SystemActivityWidget extends StatelessWidget { 7 | const SystemActivityWidget(this.activity, {super.key}); 8 | 9 | final AlarmCommentInfo activity; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | final diff = DateTime.now().difference( 14 | DateTime.fromMillisecondsSinceEpoch(activity.createdTime), 15 | ); 16 | 17 | return Column( 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | children: [ 20 | Text( 21 | timeago.format(DateTime.now().subtract(diff)), 22 | style: TbTextStyles.labelMedium.copyWith( 23 | color: Colors.black.withValues(alpha: .38), 24 | ), 25 | ), 26 | Text( 27 | activity.comment.text, 28 | style: TbTextStyles.bodyLarge.copyWith( 29 | color: Colors.black.withValues(alpha: .54), 30 | ), 31 | ), 32 | ], 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /assets/images/apple-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | --------------------------------------------------------------------------------