├── .editorconfig
├── .github
├── CODEOWNERS
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ └── feature-request.md
├── PULL_REQUEST_TEMPLATE.md
├── stale.yml
└── workflows
│ └── cid.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app
├── android-base
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ ├── AuthHelper.kt
│ │ │ ├── Bridge.kt
│ │ │ ├── HomeActivity.kt
│ │ │ ├── LinkReceiverActivity.kt
│ │ │ └── RobotScouter.kt
│ │ ├── play
│ │ ├── contact-email.txt
│ │ ├── contact-website.txt
│ │ ├── default-language.txt
│ │ ├── listings
│ │ │ ├── en-US
│ │ │ │ ├── full-description.txt
│ │ │ │ ├── graphics
│ │ │ │ │ ├── feature-graphic
│ │ │ │ │ │ └── feature.png
│ │ │ │ │ ├── icon
│ │ │ │ │ │ └── logo.png
│ │ │ │ │ ├── large-tablet-screenshots
│ │ │ │ │ │ ├── 1) Home.png
│ │ │ │ │ │ └── 2) Home 2.png
│ │ │ │ │ └── phone-screenshots
│ │ │ │ │ │ ├── 1) Home.png
│ │ │ │ │ │ ├── 2) Dark Mode.png
│ │ │ │ │ │ ├── 3) Scout Editor.png
│ │ │ │ │ │ ├── 4) Scout Editor 2.png
│ │ │ │ │ │ ├── 5) Template Editor.png
│ │ │ │ │ │ ├── 6) Template Editor 2.png
│ │ │ │ │ │ └── 7) Team Details Editor.png
│ │ │ │ ├── short-description.txt
│ │ │ │ ├── title.txt
│ │ │ │ └── video-url.txt
│ │ │ └── fr-FR
│ │ │ │ ├── full-description.txt
│ │ │ │ └── short-description.txt
│ │ └── release-notes
│ │ │ └── en-US
│ │ │ └── default.txt
│ │ └── res
│ │ ├── anim
│ │ ├── fade_in.xml
│ │ ├── fade_out.xml
│ │ ├── pop_fade_in.xml
│ │ ├── pop_fade_in_right.xml
│ │ └── pop_fade_out.xml
│ │ ├── drawable-anydpi-v25
│ │ ├── ic_shortcut_add_scout.xml
│ │ ├── ic_shortcut_export_all_teams.xml
│ │ ├── shortcut_add_scout.xml
│ │ ├── shortcut_background.xml
│ │ └── shortcut_export_all_teams.xml
│ │ ├── drawable-anydpi-v26
│ │ ├── shortcut_add_scout.xml
│ │ └── shortcut_export_all_teams.xml
│ │ ├── drawable
│ │ ├── ic_auto_fix_colorable_24dp.xml
│ │ ├── ic_content_paste_colorable_24dp.xml
│ │ ├── ic_delete_colorable_24dp.xml
│ │ ├── ic_donate_grey_24dp.xml
│ │ ├── ic_import_export_colorable_24dp.xml
│ │ ├── ic_people_colorable_24dp.xml
│ │ ├── ic_settings_colorable_24dp.xml
│ │ └── ic_sign_in_colorable_24dp.xml
│ │ ├── layout-large-land
│ │ └── activity_home.xml
│ │ ├── layout-large
│ │ └── activity_home_base.xml
│ │ ├── layout-xlarge
│ │ └── activity_home.xml
│ │ ├── layout
│ │ ├── activity_home.xml
│ │ ├── activity_home_content.xml
│ │ └── activity_link_receiver.xml
│ │ ├── menu
│ │ ├── home_bottom_navigation.xml
│ │ ├── home_drawer.xml
│ │ └── home_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values
│ │ └── strings.xml
│ │ └── xml-v25
│ │ └── shortcuts.xml
└── server
│ ├── .firebaserc
│ ├── firebase.json
│ ├── firestore.rules
│ ├── functions
│ ├── build.gradle.kts
│ ├── src
│ │ └── main
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── server
│ │ │ ├── Index.kt
│ │ │ ├── functions
│ │ │ ├── Cleanup.kt
│ │ │ ├── ClientApi.kt
│ │ │ ├── Init.kt
│ │ │ ├── Log.kt
│ │ │ ├── TeamPopulation.kt
│ │ │ ├── Templates.kt
│ │ │ └── Transfer.kt
│ │ │ └── utils
│ │ │ ├── Constants.kt
│ │ │ ├── Database.kt
│ │ │ ├── Js.kt
│ │ │ ├── Metrics.kt
│ │ │ └── types
│ │ │ ├── Auth.kt
│ │ │ ├── Firestore.kt
│ │ │ ├── Functions.kt
│ │ │ ├── Https.kt
│ │ │ ├── Pubsub.kt
│ │ │ └── Superagent.kt
│ └── upload
│ │ ├── .gitignore
│ │ ├── common
│ │ └── package.json
│ │ ├── package-lock.json
│ │ └── package.json
│ ├── storage.rules
│ └── web
│ ├── .well-known
│ └── assetlinks.json
│ ├── 404.html
│ └── index.html
├── assets
├── demo.gif
└── logo.svg
├── build.gradle.kts
├── buildSrc
├── build.gradle.kts
└── src
│ └── main
│ ├── kotlin
│ ├── Config.kt
│ ├── Projects.kt
│ └── com
│ │ └── supercilex
│ │ └── robotscouter
│ │ └── build
│ │ ├── RobotScouterBuildPlugin.kt
│ │ ├── internal
│ │ ├── Constants.kt
│ │ ├── External.kt
│ │ └── Io.kt
│ │ └── tasks
│ │ ├── DeployServer.kt
│ │ ├── GenerateChangelog.kt
│ │ ├── RebuildSecrets.kt
│ │ ├── Setup.kt
│ │ └── UpdateTranslations.kt
│ └── resources
│ └── META-INF
│ └── gradle-plugins
│ └── com.supercilex.robotscouter.build.properties
├── ci-dummies
├── config.xml
├── google-services.json
├── keystore.jks
├── keystore.properties
└── upload-keystore.properties
├── feature
├── autoscout
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── feature
│ │ │ └── autoscout
│ │ │ └── AutoScoutFragment.kt
│ │ └── res
│ │ └── layout
│ │ └── fragment_auto_scout.xml
├── exports
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── feature
│ │ │ └── exports
│ │ │ ├── ExportNotificationManager.kt
│ │ │ ├── ExportService.kt
│ │ │ ├── SpreadsheetCache.kt
│ │ │ ├── Spreadsheets.kt
│ │ │ └── TemplateExporter.kt
│ │ └── res
│ │ ├── drawable-anydpi-v23
│ │ ├── ic_done_white_24dp.xml
│ │ ├── ic_launch_white_24dp.xml
│ │ └── ic_share_white_24dp.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_done_white_24dp.png
│ │ ├── ic_launch_white_24dp.png
│ │ └── ic_share_white_24dp.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_done_white_24dp.png
│ │ ├── ic_launch_white_24dp.png
│ │ └── ic_share_white_24dp.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_done_white_24dp.png
│ │ ├── ic_launch_white_24dp.png
│ │ └── ic_share_white_24dp.png
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_done_white_24dp.png
│ │ ├── ic_launch_white_24dp.png
│ │ └── ic_share_white_24dp.png
│ │ ├── drawable
│ │ ├── ic_done_white_24dp.png
│ │ ├── ic_launch_white_24dp.png
│ │ └── ic_share_white_24dp.png
│ │ ├── values-fr
│ │ └── strings.xml
│ │ └── values
│ │ └── strings.xml
├── scouts
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── feature
│ │ │ └── scouts
│ │ │ ├── ActivityScoutListFragment.kt
│ │ │ ├── AppBarViewHolderBase.kt
│ │ │ ├── IntegratedScoutListFragment.kt
│ │ │ ├── ScoutAdapter.kt
│ │ │ ├── ScoutFragment.kt
│ │ │ ├── ScoutListActivity.kt
│ │ │ ├── ScoutListFragmentBase.kt
│ │ │ ├── ScoutPagerAdapter.kt
│ │ │ ├── ScoutTemplateSelectorDialog.kt
│ │ │ ├── TabletScoutListContainer.kt
│ │ │ ├── TabletScoutListFragment.kt
│ │ │ ├── TemplateSelectionListener.kt
│ │ │ └── viewholder
│ │ │ ├── EditTextViewHolder.kt
│ │ │ └── SpinnerViewHolder.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── ic_assignment_grey_96dp.xml
│ │ └── ic_cloud_grey_96dp.xml
│ │ ├── layout
│ │ ├── activity_scout_list.xml
│ │ ├── fragment_scout_list.xml
│ │ ├── fragment_scout_list_toolbar.xml
│ │ ├── fragment_scout_metric_list.xml
│ │ ├── scout_checkbox.xml
│ │ ├── scout_counter.xml
│ │ ├── scout_header.xml
│ │ ├── scout_notes.xml
│ │ ├── scout_spinner.xml
│ │ └── scout_stopwatch.xml
│ │ ├── menu
│ │ ├── integrated_scout_list_menu.xml
│ │ ├── scout_list_menu.xml
│ │ └── scout_options.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ └── values
│ │ └── strings.xml
├── settings
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── feature
│ │ │ └── settings
│ │ │ ├── DefaultTemplatePreference.kt
│ │ │ ├── LicensesFragment.kt
│ │ │ ├── SettingsActivity.kt
│ │ │ ├── SettingsFragment.kt
│ │ │ └── SettingsViewModel.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── ic_link_colorable_24dp.xml
│ │ ├── ic_lock_outline_colorable_24dp.xml
│ │ ├── ic_replay_colorable_24dp.xml
│ │ ├── ic_sign_out_colorable_24dp.xml
│ │ └── ic_weather_night_colorable_24dp.xml
│ │ ├── layout
│ │ ├── activity_settings.xml
│ │ └── fragment_licenses.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── app_preferences.xml
├── teams
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── feature
│ │ │ └── teams
│ │ │ ├── NewTeamDialog.kt
│ │ │ ├── Selection.kt
│ │ │ ├── SnackbarSelectionObserver.kt
│ │ │ ├── TeamListAdapter.kt
│ │ │ ├── TeamListFragment.kt
│ │ │ ├── TeamListHolder.kt
│ │ │ ├── TeamMenuHelper.kt
│ │ │ ├── TeamTemplateSelectorDialog.kt
│ │ │ ├── TeamViewHolder.kt
│ │ │ └── Tutorials.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── ic_check_circle_grey_56dp.xml
│ │ └── ic_group_grey_96dp.xml
│ │ ├── layout
│ │ ├── dialog_new_team.xml
│ │ ├── fragment_team_list.xml
│ │ └── team_list_row_layout.xml
│ │ ├── menu
│ │ └── team_options.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ └── values
│ │ ├── strings.xml
│ │ └── styles.xml
├── templates
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── feature
│ │ │ └── templates
│ │ │ ├── AddMetricDialog.kt
│ │ │ ├── DeleteTemplateDialog.kt
│ │ │ ├── NewTemplateDialog.kt
│ │ │ ├── TemplateAdapter.kt
│ │ │ ├── TemplateFragment.kt
│ │ │ ├── TemplateItemTouchCallback.kt
│ │ │ ├── TemplateListFragment.kt
│ │ │ ├── TemplatePagerAdapter.kt
│ │ │ ├── TemplateSharer.kt
│ │ │ └── viewholder
│ │ │ ├── CheckboxTemplateViewHolder.kt
│ │ │ ├── CounterTemplateViewHolder.kt
│ │ │ ├── EditTextTemplateViewHolder.kt
│ │ │ ├── HeaderTemplateViewHolder.kt
│ │ │ ├── MetricTemplateViewHolder.kt
│ │ │ ├── SpinnerTemplateViewHolder.kt
│ │ │ ├── StopwatchTemplateViewHolder.kt
│ │ │ └── TemplateViewHolder.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── ic_default_24dp.xml
│ │ ├── ic_delete_black_24dp.xml
│ │ ├── ic_header_spinner.xml
│ │ ├── ic_metric_checkbox.xml
│ │ ├── ic_metric_counter.xml
│ │ ├── ic_metric_header.xml
│ │ ├── ic_metric_notes.xml
│ │ ├── ic_metric_stopwatch.xml
│ │ ├── ic_reorder_black_24dp.xml
│ │ └── ic_ruler_grey_96dp.xml
│ │ ├── layout
│ │ ├── dialog_add_metric.xml
│ │ ├── fragment_template_list.xml
│ │ ├── fragment_template_metric_list.xml
│ │ ├── scout_template_base_reorder.xml
│ │ ├── scout_template_checkbox.xml
│ │ ├── scout_template_counter.xml
│ │ ├── scout_template_header.xml
│ │ ├── scout_template_notes.xml
│ │ ├── scout_template_spinner.xml
│ │ ├── scout_template_spinner_item.xml
│ │ └── scout_template_stopwatch.xml
│ │ ├── menu
│ │ ├── template_list_menu.xml
│ │ └── template_options.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ └── values
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── trash
│ ├── build.gradle.kts
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── supercilex
│ │ └── robotscouter
│ │ └── feature
│ │ └── trash
│ │ ├── Data.kt
│ │ ├── EmptyTrashDialog.kt
│ │ ├── SelectableScrollView.kt
│ │ ├── Selection.kt
│ │ ├── TrashActivity.kt
│ │ ├── TrashFragment.kt
│ │ ├── TrashListAdapter.kt
│ │ └── TrashViewHolder.kt
│ └── res
│ ├── drawable
│ ├── ic_close_colorable_24dp.xml
│ ├── ic_delete_empty_96dp.xml
│ ├── ic_restore_colorable_24dp.xml
│ ├── trash_item_divider.xml
│ └── trash_list_item.xml
│ ├── layout
│ ├── activity_trash.xml
│ ├── fragment_trash.xml
│ └── trash_item.xml
│ ├── menu
│ └── trash_options.xml
│ ├── values-fr
│ └── strings.xml
│ └── values
│ └── strings.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── common
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── com
│ │ └── supercilex
│ │ └── robotscouter
│ │ └── common
│ │ ├── Collections.kt
│ │ └── Constants.kt
├── core-data
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── core
│ │ │ └── data
│ │ │ ├── Analytics.kt
│ │ │ ├── Args.kt
│ │ │ ├── CachingSharer.kt
│ │ │ ├── Cleanup.kt
│ │ │ ├── Constants.kt
│ │ │ ├── Database.kt
│ │ │ ├── Io.kt
│ │ │ ├── Jobs.kt
│ │ │ ├── Links.kt
│ │ │ ├── ListenerRegistrationLifecycleOwner.kt
│ │ │ ├── Notifications.kt
│ │ │ ├── Prefs.kt
│ │ │ ├── RemoteConfig.kt
│ │ │ ├── SimpleViewModelBase.kt
│ │ │ ├── SingleLiveEvent.kt
│ │ │ ├── TaskLogging.kt
│ │ │ ├── ViewModelBase.kt
│ │ │ ├── client
│ │ │ ├── UploadTeamMedia.kt
│ │ │ └── WorkerBase.kt
│ │ │ ├── model
│ │ │ ├── Metrics.kt
│ │ │ ├── Scouts.kt
│ │ │ ├── ScoutsHolder.kt
│ │ │ ├── TeamCache.kt
│ │ │ ├── TeamHolder.kt
│ │ │ ├── Teams.kt
│ │ │ ├── Templates.kt
│ │ │ └── Users.kt
│ │ │ └── remote
│ │ │ ├── TeamMediaApi.kt
│ │ │ └── TeamMediaUploader.kt
│ │ └── res
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values
│ │ └── strings.xml
│ │ ├── xml-v29
│ │ └── file_paths.xml
│ │ └── xml
│ │ ├── file_paths.xml
│ │ └── remote_config_defaults.xml
├── core-model
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── supercilex
│ │ └── robotscouter
│ │ └── core
│ │ └── model
│ │ ├── Metric.kt
│ │ ├── MetricType.kt
│ │ ├── OrderedModel.kt
│ │ ├── OrderedRemoteModel.kt
│ │ ├── Scout.kt
│ │ ├── Team.kt
│ │ └── TemplateType.kt
├── core-ui
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── core
│ │ │ └── ui
│ │ │ ├── Animations.kt
│ │ │ ├── CardMetric.kt
│ │ │ ├── ContentLoading.kt
│ │ │ ├── Contexts.kt
│ │ │ ├── Dialogs.kt
│ │ │ ├── Drawables.kt
│ │ │ ├── Flow.kt
│ │ │ ├── Keyboard.kt
│ │ │ ├── Lifecycle.kt
│ │ │ ├── Permissions.kt
│ │ │ ├── RecyclerView.kt
│ │ │ ├── Selection.kt
│ │ │ ├── Snackbars.kt
│ │ │ ├── StateHolder.kt
│ │ │ ├── Ui.kt
│ │ │ └── views
│ │ │ ├── CardMetricConstraintLayout.kt
│ │ │ ├── CardMetricFlexboxLayout.kt
│ │ │ ├── CardMetricLinearLayout.kt
│ │ │ ├── ContentLoadingHint.kt
│ │ │ ├── ContentLoadingProgressBar.kt
│ │ │ ├── SupportVectorDrawablesImageButton.kt
│ │ │ └── UnscrollableViewPager.kt
│ │ └── res
│ │ ├── color
│ │ ├── enablable_button_icon.xml
│ │ └── list_item.xml
│ │ ├── drawable-anydpi-v23
│ │ ├── ic_logo.xml
│ │ └── launch_screen.xml
│ │ ├── drawable-hdpi
│ │ └── ic_logo.png
│ │ ├── drawable-xhdpi
│ │ └── ic_logo.png
│ │ ├── drawable-xxhdpi
│ │ └── ic_logo.png
│ │ ├── drawable-xxxhdpi
│ │ └── ic_logo.png
│ │ ├── drawable
│ │ ├── card_item_background.xml
│ │ ├── ic_logo.png
│ │ └── launch_screen.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values-large-port
│ │ └── dimens.xml
│ │ ├── values-large
│ │ └── dimens.xml
│ │ ├── values-night-v27
│ │ └── styles.xml
│ │ ├── values-night
│ │ └── colors.xml
│ │ ├── values-normal-land
│ │ └── dimens.xml
│ │ ├── values-v17
│ │ └── styles.xml
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-v26
│ │ └── styles.xml
│ │ ├── values-v27
│ │ └── styles.xml
│ │ ├── values-xlarge-land
│ │ └── dimens.xml
│ │ ├── values-xlarge-port
│ │ └── dimens.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
├── core
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── core
│ │ │ ├── Async.kt
│ │ │ ├── Connectivity.kt
│ │ │ ├── Constants.kt
│ │ │ ├── Logging.kt
│ │ │ ├── Properties.kt
│ │ │ ├── RobotScouter.kt
│ │ │ └── Toasts.kt
│ │ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── kotlinx.coroutines.CoroutineExceptionHandler
├── shared-scouting
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── supercilex
│ │ │ └── robotscouter
│ │ │ └── shared
│ │ │ └── scouting
│ │ │ ├── CounterValueDialog.kt
│ │ │ ├── MetricListAdapterBase.kt
│ │ │ ├── MetricListFragment.kt
│ │ │ ├── MetricListHolder.kt
│ │ │ ├── MetricViewHolderBase.kt
│ │ │ ├── TabNameDialog.kt
│ │ │ ├── TabPagerAdapterBase.kt
│ │ │ ├── ValueDialogBase.kt
│ │ │ └── viewholder
│ │ │ ├── CheckboxViewHolder.kt
│ │ │ ├── CounterViewHolder.kt
│ │ │ ├── HeaderViewHolder.kt
│ │ │ └── StopwatchViewHolder.kt
│ │ └── res
│ │ ├── color
│ │ ├── activatable_button_text.xml
│ │ └── button_outline.xml
│ │ ├── drawable-anydpi-v21
│ │ └── button_outline_colored.xml
│ │ ├── drawable-v21
│ │ ├── ic_timer_off_to_on_24dp.xml
│ │ └── ic_timer_on_to_off_24dp.xml
│ │ ├── drawable
│ │ ├── button_outline_colored.xml
│ │ ├── ic_remove_colorable_24dp.xml
│ │ ├── ic_timer_off_24dp.xml
│ │ └── ic_timer_on_24dp.xml
│ │ ├── layout
│ │ ├── dialog_value.xml
│ │ ├── scout_base_checkbox.xml
│ │ ├── scout_base_counter.xml
│ │ ├── scout_base_stopwatch.xml
│ │ └── scout_stopwatch_cycle_item.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values-v17
│ │ └── styles.xml
│ │ └── values
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── shared
│ ├── build.gradle.kts
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── supercilex
│ │ └── robotscouter
│ │ └── shared
│ │ ├── CardListHelper.kt
│ │ ├── CustomTabs.kt
│ │ ├── MovableFragmentStatePagerAdapter.kt
│ │ ├── RatingDialog.kt
│ │ ├── SharedLifecycleResource.kt
│ │ ├── ShouldUploadMediaToTbaDialog.kt
│ │ ├── TeamDetailsDialog.kt
│ │ ├── TeamMediaCreator.kt
│ │ ├── TeamSharer.kt
│ │ ├── TemplateSelectorDialog.kt
│ │ ├── Ui.kt
│ │ └── client
│ │ ├── AccountMergeService.kt
│ │ ├── AppIndexing.kt
│ │ └── Auth.kt
│ └── res
│ ├── anim
│ ├── slide_in_left.xml
│ └── slide_out_right.xml
│ ├── color
│ └── empty_icon_list_item.xml
│ ├── drawable
│ ├── ic_add_a_photo_colorable_24dp.xml
│ ├── ic_add_colorable_24dp.xml
│ ├── ic_check_grey_24dp.xml
│ ├── ic_content_paste_grey_96dp.xml
│ ├── ic_delete_forever_colorable_24dp.xml
│ ├── ic_info_colorable_24dp.xml
│ ├── ic_launch_accent_24dp.xml
│ ├── ic_mode_edit_colorable_24dp.xml
│ ├── ic_person_grey_96dp.xml
│ ├── ic_share_colorable_24dp.xml
│ └── ic_star_accent_24dp.xml
│ ├── layout
│ ├── dialog_should_upload_media.xml
│ ├── dialog_team_details.xml
│ └── dialog_template_selector.xml
│ ├── values-fr
│ └── strings.xml
│ └── values
│ ├── font_certs.xml
│ └── strings.xml
├── secrets.tar.enc
└── settings.gradle.kts
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @SUPERCILEX
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: SUPERCILEX
2 | ko_fi: supercilex
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Help improve Robot Scouter
4 | ---
5 |
6 |
15 |
16 | ### Step 1: Describe your environment
17 |
18 |
22 |
23 | ### Step 2: Describe the problem:
24 |
25 | #### Steps to reproduce:
26 |
27 | 1. _____
28 | 2. _____
29 | 3. _____
30 |
31 | #### Observed Results:
32 |
33 |
34 |
35 | #### Expected Results:
36 |
37 |
38 |
39 | #### Other Relevant Bits:
40 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea
4 | ---
5 |
6 |
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 |
12 |
15 |
16 | **Describe the solution you'd like**
17 |
18 |
21 |
22 | **Describe alternatives you've considered**
23 |
24 |
27 |
28 | **Additional context**
29 |
30 |
33 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Hey there! So you want to contribute to Robot Scouter?
2 | Before you file this pull request, follow these steps:
3 |
4 | - Read [the contribution guidelines](https://github.com/SUPERCILEX/Robot-Scouter/blob/master/.github/CONTRIBUTING.md).
5 | - If this has been discussed in an issue, make sure to mention the issue number here.
6 | If not, go file an issue about this to make sure this is a desirable change.
7 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | daysUntilStale: 7
2 | daysUntilClose: 7
3 | exemptLabels:
4 | - feature
5 | - enhancement
6 | - bug
7 | - refactor
8 | staleLabel: stale
9 | markComment: >
10 | This issue has been automatically marked as stale because it has not had
11 | recent activity. It will be closed if no further activity occurs. Thank you
12 | for your contributions.
13 | closeComment: false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | .idea/*
4 | build
5 | !**/src/**/build
6 | node_modules
7 | .firebase
8 | /local.properties
9 |
10 | *keystore.properties
11 | google-*.json
12 | *.jks
13 | config.xml
14 | !ci-dummies/*.*
15 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Want to contribute? Awesome!
2 |
3 | ### Before you contribute
4 |
5 | Before we can use your code, you must sign the
6 | [SUPERCILEX Individual Contributor License Agreement](https://cla-assistant.io/SUPERCILEX/Robot-Scouter),
7 | which you can do online. The CLA is necessary mainly because you own the copyright to your changes,
8 | even after your contribution becomes part of our codebase, so we need your permission to use and
9 | distribute your code. We also need to be sure of various other things—for instance that you'll tell
10 | us if you know that your code infringes on other people's patents. You don't have to sign the CLA
11 | until after you've submitted your code for review and a member has approved it, but you must do it
12 | before we can put your code into our codebase.
13 |
14 | ### Adding new features
15 |
16 | Before you start working on a larger contribution, you should get in touch with us first through the
17 | issue tracker with your idea so that we can help out and possibly guide you. Coordinating up front
18 | makes it much easier to avoid frustration later on.
19 |
20 | If this has been discussed in an issue, make sure to mention the issue number. If not, go file an
21 | issue about this to make sure this is a desirable change.
22 |
23 | ### Code reviews
24 |
25 | All submissions, including submissions by project members, require review. We adhere to the
26 | [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html).
27 |
--------------------------------------------------------------------------------
/app/android-base/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Keeps line numbers and file name obfuscation
2 | -renamesourcefileattribute SourceFile
3 | -keepattributes SourceFile,LineNumberTable
4 | -printconfiguration build/outputs/mapping/configuration.txt
5 |
6 | # Keep bridges
7 | -keep class com.supercilex.robotscouter.Bridge
8 | -keep @com.supercilex.robotscouter.Bridge class * {
9 | *** Companion;
10 | }
11 |
12 | # Ignore Kotlin errors TODO https://youtrack.jetbrains.com/issue/KT-23172
13 | -dontwarn com.supercilex.robotscouter.**
14 | -dontwarn kotlinx.**
15 |
16 | # Remove logging
17 | -assumenosideeffects class android.util.Log {
18 | public static boolean isLoggable(java.lang.String, int);
19 | public static int v(...);
20 | public static int i(...);
21 | public static int w(...);
22 | public static int d(...);
23 | public static int e(...);
24 | }
25 |
26 | # Apache POI - TODO remove once the next POIA version comes out
27 | -keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellProtection { *; }
28 | -keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellProtectionImpl { *; }
29 | -keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.STBorderStyle$Enum { *; }
30 |
--------------------------------------------------------------------------------
/app/android-base/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Robot Scouter DEBUG
4 |
5 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/contact-email.txt:
--------------------------------------------------------------------------------
1 | robotscouter@supercilex.com
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/contact-website.txt:
--------------------------------------------------------------------------------
1 | https://github.com/SUPERCILEX/Robot-Scouter/
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/default-language.txt:
--------------------------------------------------------------------------------
1 | en-US
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/feature-graphic/feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/feature-graphic/feature.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/icon/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/icon/logo.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/large-tablet-screenshots/1) Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/large-tablet-screenshots/1) Home.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/large-tablet-screenshots/2) Home 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/large-tablet-screenshots/2) Home 2.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/1) Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/1) Home.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/2) Dark Mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/2) Dark Mode.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/3) Scout Editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/3) Scout Editor.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/4) Scout Editor 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/4) Scout Editor 2.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/5) Template Editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/5) Template Editor.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/6) Template Editor 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/6) Template Editor 2.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/7) Team Details Editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/play/listings/en-US/graphics/phone-screenshots/7) Team Details Editor.png
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/short-description.txt:
--------------------------------------------------------------------------------
1 | Easy, efficient, and collaborative FIRST robot scouting
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Robot Scouter - FRC Scouting
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/en-US/video-url.txt:
--------------------------------------------------------------------------------
1 | https://www.youtube.com/watch?v=0tYVCfPrdGY
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/listings/fr-FR/short-description.txt:
--------------------------------------------------------------------------------
1 | Repérage de robot FIRST facile, efficace et collaboratif
2 |
--------------------------------------------------------------------------------
/app/android-base/src/main/play/release-notes/en-US/default.txt:
--------------------------------------------------------------------------------
1 | Robot Scouter v3.0 is out!!! v3.0 completely reworks Robot Scouter's user experience, supports trashing teams and templates instead of permanently deleting them, includes rewritten internals to make future development easier, and fixes swaths of bugs.
2 |
3 | For more details, see the full release notes: https://github.com/SUPERCILEX/Robot-Scouter/releases.
4 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/anim/pop_fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
12 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/anim/pop_fade_in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/anim/pop_fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v25/ic_shortcut_add_scout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v25/ic_shortcut_export_all_teams.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v25/shortcut_add_scout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v25/shortcut_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v25/shortcut_export_all_teams.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v26/shortcut_add_scout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable-anydpi-v26/shortcut_export_all_teams.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_auto_fix_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_content_paste_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_delete_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_donate_grey_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_import_export_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_people_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_settings_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/drawable/ic_sign_in_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/layout-large-land/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/layout-xlarge/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/layout/activity_link_receiver.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/menu/home_bottom_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/menu/home_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
35 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/menu/home_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap/ic_launcher.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android-base/src/main/res/mipmap/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/app/android-base/src/main/res/mipmap/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/server/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "robot-scouter-app"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/app/server/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "firestore": {
3 | "rules": "firestore.rules"
4 | },
5 | "storage": {
6 | "rules": "storage.rules"
7 | },
8 | "hosting": {
9 | "public": "web",
10 | "ignore": [
11 | "firebase.json",
12 | "**/.*",
13 | "**/node_modules/**"
14 | ]
15 | },
16 | "functions": {
17 | "source": "functions/upload"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/server/functions/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("org.jetbrains.kotlin.js")
3 | }
4 |
5 | kotlin {
6 | target {
7 | useCommonJs()
8 | nodejs()
9 | }
10 | }
11 |
12 | dependencies {
13 | implementation(project(":library:common"))
14 |
15 | implementation(Config.Libs.Kotlin.js)
16 | implementation(Config.Libs.Kotlin.coroutinesJs)
17 | }
18 |
19 | tasks.named("clean") {
20 | delete("upload/index.js", "upload/common/index.js")
21 | delete("upload/node_modules")
22 | }
23 |
--------------------------------------------------------------------------------
/app/server/functions/src/main/kotlin/com/supercilex/robotscouter/server/utils/Js.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.server.utils
2 |
3 | import kotlin.js.Json
4 |
5 | fun Json.toMap(): Map {
6 | @Suppress("SENSELESS_COMPARISON") // JavaScrip sucks
7 | if (this == null) return emptyMap()
8 |
9 | val map: MutableMap = mutableMapOf()
10 | for (key: String in js("Object").keys(this)) {
11 | @Suppress("UNCHECKED_CAST") // Trust the client
12 | map[key] = this[key] as T
13 | }
14 | return map
15 | }
16 |
--------------------------------------------------------------------------------
/app/server/functions/src/main/kotlin/com/supercilex/robotscouter/server/utils/types/Https.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS",
6 | "unused"
7 | )
8 |
9 | package com.supercilex.robotscouter.server.utils.types
10 |
11 | import kotlin.js.Promise
12 |
13 | @Suppress("FunctionName", "UNUSED_PARAMETER", "UNUSED_VARIABLE") // Fake class
14 | fun HttpsError(code: String, message: String? = null, details: Any? = null): Throwable {
15 | val functions = functions
16 | return js("new functions.https.HttpsError(code, message, details)")
17 | }
18 |
19 | external class Https {
20 | fun onCall(handler: (data: T, context: CallableContext) -> Promise<*>?): dynamic = definedExternally
21 | }
22 |
23 | external interface CallableContext {
24 | val auth: AuthContext? get() = definedExternally
25 | val instanceIdToken: String? get() = definedExternally
26 | }
27 |
--------------------------------------------------------------------------------
/app/server/functions/src/main/kotlin/com/supercilex/robotscouter/server/utils/types/Pubsub.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS",
6 | "unused"
7 | )
8 |
9 | package com.supercilex.robotscouter.server.utils.types
10 |
11 | import kotlin.js.Json
12 | import kotlin.js.Promise
13 |
14 | external class Pubsub {
15 | fun topic(topic: String): TopicBuilder = definedExternally
16 | }
17 |
18 | external class TopicBuilder {
19 | fun onPublish(handler: (message: Message, context: EventContext) -> Promise<*>?): dynamic = definedExternally
20 | }
21 |
22 | external class Message(data: Any) {
23 | val data: String = definedExternally
24 | val json: Json = definedExternally
25 | }
26 |
--------------------------------------------------------------------------------
/app/server/functions/upload/.gitignore:
--------------------------------------------------------------------------------
1 | index.js
2 |
--------------------------------------------------------------------------------
/app/server/functions/upload/common/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Robot-Scouter-common-server",
3 | "version": "1.0.0",
4 | "private": true
5 | }
6 |
--------------------------------------------------------------------------------
/app/server/functions/upload/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "functions",
3 | "description": "Cloud Functions for Firebase",
4 | "dependencies": {
5 | "@google-cloud/firestore": "3.7.1",
6 | "Robot-Scouter-common-server": "file:./common",
7 | "firebase-admin": "8.10.0",
8 | "firebase-functions": "3.3.0",
9 | "kotlin": "1.3.70",
10 | "kotlinx-coroutines-core": "1.3.4",
11 | "lru-cache": "5.1.1",
12 | "moment": "2.24.0",
13 | "superagent": "5.2.2"
14 | },
15 | "private": true,
16 | "engines": {
17 | "node": "8"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/server/storage.rules:
--------------------------------------------------------------------------------
1 | service firebase.storage {
2 | match /b/robot-scouter-app.appspot.com/o {
3 | match /share_team_template.html {
4 | allow read;
5 | }
6 |
7 | match /share_template_template.html {
8 | allow read;
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/server/web/.well-known/assetlinks.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "relation": [
4 | "delegate_permission/common.handle_all_urls"
5 | ],
6 | "target": {
7 | "namespace": "android_app",
8 | "package_name": "com.supercilex.robotscouter",
9 | "sha256_cert_fingerprints": [
10 | "AB:0B:BC:EB:D1:4C:73:91:3E:A5:6B:04:80:88:87:30:A2:9F:7C:BD:E9:6D:16:D4:AA:90:90:DB:A5:08:69:DD"
11 | ]
12 | }
13 | },
14 | {
15 | "relation": [
16 | "delegate_permission/common.get_login_creds"
17 | ],
18 | "target": {
19 | "namespace": "web",
20 | "site": "https://supercilex.github.io"
21 | }
22 | },
23 | {
24 | "relation": [
25 | "delegate_permission/common.get_login_creds"
26 | ],
27 | "target": {
28 | "namespace": "android_app",
29 | "package_name": "com.supercilex.robotscouter",
30 | "sha256_cert_fingerprints": [
31 | "AB:0B:BC:EB:D1:4C:73:91:3E:A5:6B:04:80:88:87:30:A2:9F:7C:BD:E9:6D:16:D4:AA:90:90:DB:A5:08:69:DD"
32 | ]
33 | }
34 | }
35 | ]
36 |
--------------------------------------------------------------------------------
/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/assets/demo.gif
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | repositories {
2 | google()
3 | jcenter()
4 | }
5 |
6 | plugins {
7 | `kotlin-dsl`
8 | }
9 |
10 | tasks.withType().configureEach {
11 | enableStricterValidation.set(true)
12 | }
13 |
14 | dependencies {
15 | implementation("org.ajoberstar.grgit:grgit-gradle:4.0.1")
16 | implementation("com.google.cloud:google-cloud-pubsub:1.102.0")
17 |
18 | // TODO remove when GPP 2.7 ships
19 | implementation("com.google.guava:guava:28.1-jre")
20 | }
21 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/Projects.kt:
--------------------------------------------------------------------------------
1 | import com.supercilex.robotscouter.build.internal.isCi
2 | import com.supercilex.robotscouter.build.internal.isRelease
3 | import org.gradle.api.Project
4 |
5 | val Project.buildTags: List
6 | get() = listOf(
7 | if (isCi) "CI" else "Local",
8 | if (isRelease) "Release" else "Debug",
9 | if (isReleaseBuild) "ProdBuild" else "DevBuild"
10 | )
11 |
12 | val Project.isReleaseBuild: Boolean get() = hasProperty("relBuild") || isCi
13 |
14 | internal fun Project.child(name: String): Project = subprojects.first { it.name == name }
15 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/com/supercilex/robotscouter/build/internal/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.build.internal
2 |
3 | import child
4 | import org.gradle.api.Task
5 | import org.gradle.api.file.RegularFile
6 |
7 | internal val isCi = System.getenv("CI") != null
8 | internal val isRelease = System.getenv("ROBOT_SCOUTER_RELEASE") != null
9 |
10 | internal val Task.secrets: Secrets
11 | get() {
12 | val rootProject = project.rootProject
13 | val android = rootProject.child("android-base").layout.projectDirectory
14 |
15 | val ci = listOf(
16 | android.file("upload-keystore.jks"),
17 | android.file("upload-keystore.properties"),
18 | android.file("google-services.json"),
19 | android.file("google-play-auto-publisher.json"),
20 | rootProject.child("core-data").layout.projectDirectory
21 | .file("src/main/res/values/config.xml")
22 | )
23 | val full = ci + listOf(
24 | android.file("keystore.jks"),
25 | android.file("keystore.properties")
26 | )
27 |
28 | return Secrets(full, ci)
29 | }
30 |
31 | internal data class Secrets(val full: List, val ci: List)
32 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/com/supercilex/robotscouter/build/internal/External.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.build.internal
2 |
3 | import org.eclipse.jgit.util.io.NullOutputStream
4 | import org.gradle.process.ExecSpec
5 |
6 | internal fun ExecSpec.redactLogs() {
7 | standardOutput = NullOutputStream.INSTANCE
8 | errorOutput = NullOutputStream.INSTANCE
9 | }
10 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/com/supercilex/robotscouter/build/internal/Io.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.build.internal
2 |
3 | import java.io.File
4 |
5 | internal fun File.orNull() = takeIf { exists() }
6 |
--------------------------------------------------------------------------------
/buildSrc/src/main/resources/META-INF/gradle-plugins/com.supercilex.robotscouter.build.properties:
--------------------------------------------------------------------------------
1 | implementation-class=com.supercilex.robotscouter.build.RobotScouterBuildPlugin
2 |
--------------------------------------------------------------------------------
/ci-dummies/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TODO
5 | TODO
6 | TODO
7 | TODO
8 | TODO
9 | TODO
10 | TODO.firebaseapp.com
11 | Client-ID TODO
12 | TODO
13 |
14 |
--------------------------------------------------------------------------------
/ci-dummies/keystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/ci-dummies/keystore.jks
--------------------------------------------------------------------------------
/ci-dummies/keystore.properties:
--------------------------------------------------------------------------------
1 | keyAlias=keystore
2 | keyPassword=000000
3 | storeFile=keystore.jks
4 | storePassword=000000
5 |
--------------------------------------------------------------------------------
/ci-dummies/upload-keystore.properties:
--------------------------------------------------------------------------------
1 | keyAlias=keystore
2 | keyPassword=000000
3 | storeFile=keystore.jks
4 | storePassword=000000
5 |
--------------------------------------------------------------------------------
/feature/autoscout/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared"))
4 |
5 | implementation(Config.Libs.PlayServices.nearby)
6 | }
7 |
--------------------------------------------------------------------------------
/feature/autoscout/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
24 |
25 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/feature/autoscout/src/main/java/com/supercilex/robotscouter/feature/autoscout/AutoScoutFragment.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.autoscout
2 |
3 | import androidx.fragment.app.FragmentManager
4 | import com.supercilex.robotscouter.AutoScoutFragmentCompanion
5 | import com.supercilex.robotscouter.AutoScoutFragmentCompanion.Companion.TAG
6 | import com.supercilex.robotscouter.Bridge
7 | import com.supercilex.robotscouter.core.ui.FragmentBase
8 |
9 | @Bridge
10 | internal class AutoScoutFragment : FragmentBase(R.layout.fragment_auto_scout) {
11 | companion object : AutoScoutFragmentCompanion {
12 | override fun getInstance(manager: FragmentManager) =
13 | manager.findFragmentByTag(TAG) as AutoScoutFragment? ?: AutoScoutFragment()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/feature/autoscout/src/main/res/layout/fragment_auto_scout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/feature/exports/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared"))
4 |
5 | implementation(Config.Libs.Misc.poi)
6 | implementation(Config.Libs.Misc.poiProguard)
7 | implementation(Config.Libs.Misc.gson)
8 | }
9 |
--------------------------------------------------------------------------------
/feature/exports/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-anydpi-v23/ic_done_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-anydpi-v23/ic_launch_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-anydpi-v23/ic_share_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-hdpi/ic_done_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-hdpi/ic_done_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-hdpi/ic_launch_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-hdpi/ic_launch_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-hdpi/ic_share_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-hdpi/ic_share_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xhdpi/ic_done_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xhdpi/ic_done_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xhdpi/ic_launch_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xhdpi/ic_launch_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xhdpi/ic_share_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xhdpi/ic_share_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xxhdpi/ic_done_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xxhdpi/ic_done_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xxhdpi/ic_launch_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xxhdpi/ic_launch_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xxhdpi/ic_share_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xxhdpi/ic_share_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xxxhdpi/ic_done_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xxxhdpi/ic_done_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xxxhdpi/ic_launch_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xxxhdpi/ic_launch_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable-xxxhdpi/ic_share_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable-xxxhdpi/ic_share_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable/ic_done_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable/ic_done_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable/ic_launch_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable/ic_launch_white_24dp.png
--------------------------------------------------------------------------------
/feature/exports/src/main/res/drawable/ic_share_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/feature/exports/src/main/res/drawable/ic_share_white_24dp.png
--------------------------------------------------------------------------------
/feature/scouts/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared-scouting"))
4 |
5 | implementation(Config.Libs.Jetpack.palette)
6 | }
7 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/java/com/supercilex/robotscouter/feature/scouts/ScoutTemplateSelectorDialog.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.scouts
2 |
3 | import androidx.fragment.app.FragmentManager
4 | import com.supercilex.robotscouter.shared.TemplateSelectorDialog
5 |
6 | internal class ScoutTemplateSelectorDialog : TemplateSelectorDialog() {
7 | override fun onItemSelected(id: String) {
8 | super.onItemSelected(id)
9 | (requireParentFragment() as TemplateSelectionListener).onTemplateSelected(id)
10 | }
11 |
12 | companion object {
13 | private const val TAG = "ScoutTemplateSelector"
14 |
15 | fun show(manager: FragmentManager) = ScoutTemplateSelectorDialog().show(manager, TAG)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/java/com/supercilex/robotscouter/feature/scouts/TabletScoutListContainer.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.scouts
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.commitNow
6 | import com.supercilex.robotscouter.Bridge
7 | import com.supercilex.robotscouter.TabletScoutListFragmentCompanion
8 | import com.supercilex.robotscouter.core.ui.FragmentBase
9 |
10 | @Bridge
11 | internal class TabletScoutListContainer : FragmentBase(R.layout.activity_scout_list) {
12 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
13 | if (savedInstanceState == null) {
14 | childFragmentManager.commitNow {
15 | add(R.id.scoutList,
16 | TabletScoutListFragment.newInstance(requireArguments()),
17 | TabletScoutListFragment.TAG)
18 | }
19 | }
20 | }
21 |
22 | companion object : TabletScoutListFragmentCompanion {
23 | override fun newInstance(args: Bundle) =
24 | TabletScoutListContainer().apply { arguments = args }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/java/com/supercilex/robotscouter/feature/scouts/TemplateSelectionListener.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.scouts
2 |
3 | interface TemplateSelectionListener {
4 | fun onTemplateSelected(id: String)
5 | }
6 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/drawable/ic_assignment_grey_96dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/activity_scout_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/fragment_scout_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/fragment_scout_metric_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/scout_checkbox.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/scout_counter.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/scout_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/scout_notes.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/scout_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/layout/scout_stopwatch.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/menu/integrated_scout_list_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/menu/scout_list_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/menu/scout_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hors connexion. Les données seront sauvegardées
4 | Les repérages ajoutés apparaissent ici
5 |
6 | Nouveau repérage
7 | Ajouter un repérage
8 | Ajouter un média
9 | Modifier le modèle de repérage suivant
10 | Envoyer à une nouvelle fenêtre
11 | Accès refusé : modèle possédé par un autre utilisateur
12 |
13 | Modifier le nom du match
14 | Supprimer le repérage
15 | Repérage supprimé
16 |
17 |
--------------------------------------------------------------------------------
/feature/scouts/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Offline. Data will be saved
4 | Scouts you add appear here
5 |
6 | New scout
7 | Add scout
8 | Add media
9 | Edit next scout template
10 | Move to new window
11 |
12 | Access denied: template owned by another user
13 |
14 |
15 | Edit match name
16 | Delete scout
17 | Scout deleted
18 |
19 |
--------------------------------------------------------------------------------
/feature/settings/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared"))
4 |
5 | implementation(Config.Libs.Jetpack.pref)
6 | implementation(Config.Libs.Misc.licenses)
7 | }
8 |
--------------------------------------------------------------------------------
/feature/settings/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/feature/settings/src/main/java/com/supercilex/robotscouter/feature/settings/SettingsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.settings
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.SavedStateHandle
6 | import androidx.lifecycle.viewModelScope
7 | import com.bumptech.glide.Glide
8 | import com.supercilex.robotscouter.core.CrashLogger
9 | import com.supercilex.robotscouter.core.RobotScouter
10 | import com.supercilex.robotscouter.core.data.SimpleViewModelBase
11 | import com.supercilex.robotscouter.core.data.cleanup
12 | import com.supercilex.robotscouter.shared.client.idpSignOut
13 | import kotlinx.coroutines.launch
14 |
15 | internal class SettingsViewModel(state: SavedStateHandle) : SimpleViewModelBase(state) {
16 | private val _signOutListener = MutableLiveData()
17 | val signOutListener: LiveData = _signOutListener
18 |
19 | fun signOut() {
20 | cleanup()
21 | Glide.get(RobotScouter).clearMemory()
22 |
23 | viewModelScope.launch {
24 | try {
25 | idpSignOut()
26 | _signOutListener.value = null
27 | } catch (e: Exception) {
28 | _signOutListener.value = e
29 | CrashLogger.onFailure(e)
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/drawable/ic_link_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/drawable/ic_lock_outline_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/drawable/ic_replay_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/drawable/ic_sign_out_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/drawable/ic_weather_night_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/layout/fragment_licenses.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/feature/settings/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/feature/teams/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared"))
4 |
5 | implementation(Config.Libs.Misc.glideRv)
6 | implementation(Config.Libs.Misc.mttp)
7 | }
8 |
--------------------------------------------------------------------------------
/feature/teams/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/feature/teams/src/main/java/com/supercilex/robotscouter/feature/teams/TeamListHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.teams
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.SavedStateHandle
5 | import com.supercilex.robotscouter.core.data.SimpleViewModelBase
6 | import com.supercilex.robotscouter.core.data.TEAM_KEY
7 | import com.supercilex.robotscouter.core.data.teams
8 | import com.supercilex.robotscouter.core.model.Team
9 |
10 | internal class TeamListHolder(state: SavedStateHandle) : SimpleViewModelBase(state) {
11 | private val _selectedTeamIdListener = state.getLiveData(TEAM_KEY)
12 | val selectedTeamIdListener: LiveData get() = _selectedTeamIdListener
13 |
14 | override fun onCreate() {
15 | teams.keepAlive = true
16 | }
17 |
18 | fun selectTeam(team: Team?) {
19 | _selectedTeamIdListener.value = team
20 | }
21 |
22 | override fun onCleared() {
23 | super.onCleared()
24 | teams.keepAlive = false
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/feature/teams/src/main/java/com/supercilex/robotscouter/feature/teams/TeamTemplateSelectorDialog.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.teams
2 |
3 | import androidx.fragment.app.FragmentManager
4 | import com.supercilex.robotscouter.TeamSelectionListener
5 | import com.supercilex.robotscouter.core.data.getScoutBundle
6 | import com.supercilex.robotscouter.core.data.getTeam
7 | import com.supercilex.robotscouter.core.data.toBundle
8 | import com.supercilex.robotscouter.core.model.Team
9 | import com.supercilex.robotscouter.core.ui.show
10 | import com.supercilex.robotscouter.shared.TemplateSelectorDialog
11 |
12 | internal class TeamTemplateSelectorDialog : TemplateSelectorDialog() {
13 | override fun onItemSelected(id: String) {
14 | super.onItemSelected(id)
15 | (context as TeamSelectionListener)
16 | .onTeamSelected(getScoutBundle(requireArguments().getTeam(), true, id))
17 | }
18 |
19 | companion object {
20 | private const val TAG = "TeamTemplateSelector"
21 |
22 | fun show(manager: FragmentManager, team: Team) =
23 | TeamTemplateSelectorDialog().show(manager, TAG, team.toBundle())
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/drawable/ic_check_circle_grey_56dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/drawable/ic_group_grey_96dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/layout/dialog_new_team.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/layout/fragment_team_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/menu/team_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
33 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Numéro de l\'équipe
4 | Exporter les équipes
5 | Les équipes ajoutées apparaissent ici
6 |
7 | Inconnu
8 |
9 | - Équipe supprimée
10 | - %s équipes supprimées
11 |
12 |
13 | Tout sélectionner
14 | Plusieurs équipes sélectionnées
15 |
16 | Créer votre première équipe
17 | Se connecter
18 | Se connecter vous permet de synchroniser vos données avec d\'autres appareils à travers votre équipe.
19 |
20 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Team number
4 | Export teams
5 | Teams you add appear here
6 |
7 | Unknown
8 |
9 | - Team deleted
10 | - %s teams deleted
11 |
12 |
13 | Select all
14 | Multiple teams selected
15 |
16 | Create your first team
17 | Sign in
18 |
19 | Signing in lets you easily sync data with other devices across your team.
20 |
21 |
22 |
--------------------------------------------------------------------------------
/feature/teams/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared-scouting"))
4 |
5 | implementation(Config.Libs.Firebase.links)
6 | }
7 |
--------------------------------------------------------------------------------
/feature/templates/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/NewTemplateDialog.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates
2 |
3 | import android.content.DialogInterface
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AlertDialog
6 | import androidx.fragment.app.FragmentManager
7 | import com.supercilex.robotscouter.core.data.model.addTemplate
8 | import com.supercilex.robotscouter.core.model.TemplateType
9 | import com.supercilex.robotscouter.core.ui.DialogFragmentBase
10 | import com.supercilex.robotscouter.R as RC
11 |
12 | internal class NewTemplateDialog : DialogFragmentBase(), DialogInterface.OnClickListener {
13 | override fun onCreateDialog(savedInstanceState: Bundle?) = AlertDialog.Builder(requireContext())
14 | .setTitle(R.string.template_new_title)
15 | .setItems(RC.array.template_new_options, this)
16 | .setNegativeButton(android.R.string.cancel, null)
17 | .create()
18 |
19 | override fun onClick(dialog: DialogInterface, which: Int) {
20 | (requireParentFragment() as TemplateListFragment)
21 | .onTemplateCreated(addTemplate(TemplateType.valueOf(which)))
22 | }
23 |
24 | companion object {
25 | private const val TAG = "NewTemplateDialog"
26 |
27 | fun show(manager: FragmentManager) = NewTemplateDialog().show(manager, TAG)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/TemplatePagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.google.android.material.tabs.TabLayout
5 | import com.google.firebase.firestore.Query
6 | import com.supercilex.robotscouter.core.data.model.getTemplatesQuery
7 | import com.supercilex.robotscouter.core.data.templatesRef
8 | import com.supercilex.robotscouter.core.ui.LifecycleAwareLazy
9 | import com.supercilex.robotscouter.core.ui.onDestroy
10 | import com.supercilex.robotscouter.shared.scouting.TabPagerAdapterBase
11 | import com.supercilex.robotscouter.R as RC
12 |
13 | internal open class TemplatePagerAdapter(fragment: Fragment) :
14 | TabPagerAdapterBase(fragment, templatesRef) {
15 | override val editTabNameRes = R.string.template_edit_name_title
16 | override val tabs: TabLayout by fragment.LifecycleAwareLazy {
17 | fragment.requireActivity().findViewById(R.id.tabs)
18 | } onDestroy {
19 | it.setupWithViewPager(null)
20 | }
21 |
22 | init {
23 | holder.init { getTemplatesQuery(Query.Direction.DESCENDING) }
24 | init()
25 | }
26 |
27 | override fun getItem(position: Int) = TemplateFragment.newInstance(currentScouts[position].id)
28 |
29 | override fun getPageTitle(position: Int): String =
30 | fragment.getString(RC.string.template_tab_default_title, count - position)
31 | }
32 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/viewholder/CheckboxTemplateViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates.viewholder
2 |
3 | import android.view.View
4 | import android.widget.CheckBox
5 | import android.widget.EditText
6 | import android.widget.ImageView
7 | import com.supercilex.robotscouter.core.data.model.update
8 | import com.supercilex.robotscouter.core.data.model.updateName
9 | import com.supercilex.robotscouter.core.model.Metric
10 | import com.supercilex.robotscouter.core.unsafeLazy
11 | import com.supercilex.robotscouter.shared.scouting.viewholder.CheckboxViewHolder
12 | import kotlinx.android.synthetic.main.scout_template_base_reorder.*
13 | import com.supercilex.robotscouter.R as RC
14 |
15 | internal class CheckboxTemplateViewHolder(itemView: View) : CheckboxViewHolder(itemView),
16 | MetricTemplateViewHolder {
17 | override val reorderView: ImageView by unsafeLazy { reorder }
18 | override val nameEditor = name as EditText
19 |
20 | private val checkBox: CheckBox = containerView.findViewById(RC.id.checkBox)
21 |
22 | init {
23 | init()
24 | name.setOnClickListener(null)
25 | }
26 |
27 | override fun onClick(v: View) {
28 | if (name.hasFocus()) metric.updateName(name.text.toString())
29 | if (v.id == RC.id.checkBox) metric.update(checkBox.isChecked)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/viewholder/EditTextTemplateViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates.viewholder
2 |
3 | import android.view.View
4 | import android.widget.EditText
5 | import android.widget.ImageView
6 | import com.supercilex.robotscouter.core.data.model.update
7 | import com.supercilex.robotscouter.core.model.Metric
8 | import com.supercilex.robotscouter.core.unsafeLazy
9 | import com.supercilex.robotscouter.shared.scouting.MetricViewHolderBase
10 | import kotlinx.android.synthetic.main.scout_template_base_reorder.*
11 | import kotlinx.android.synthetic.main.scout_template_notes.*
12 |
13 | internal class EditTextTemplateViewHolder(
14 | itemView: View
15 | ) : MetricViewHolderBase(itemView),
16 | MetricTemplateViewHolder {
17 | override val reorderView: ImageView by unsafeLazy { reorder }
18 | override val nameEditor = name as EditText
19 |
20 | init {
21 | init()
22 | text.onFocusChangeListener = this
23 | }
24 |
25 | override fun bind() {
26 | super.bind()
27 | text.setText(metric.value)
28 | }
29 |
30 | override fun onFocusChange(v: View, hasFocus: Boolean) {
31 | super.onFocusChange(v, hasFocus)
32 | if (!hasFocus && v === text) metric.update(text.text.toString())
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/viewholder/HeaderTemplateViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates.viewholder
2 |
3 | import android.view.View
4 | import android.widget.EditText
5 | import android.widget.ImageView
6 | import com.supercilex.robotscouter.core.model.Metric
7 | import com.supercilex.robotscouter.core.unsafeLazy
8 | import com.supercilex.robotscouter.shared.scouting.viewholder.HeaderViewHolder
9 | import kotlinx.android.synthetic.main.scout_template_base_reorder.*
10 |
11 | internal class HeaderTemplateViewHolder(itemView: View) : HeaderViewHolder(itemView),
12 | MetricTemplateViewHolder {
13 | override val reorderView: ImageView by unsafeLazy { reorder }
14 | override val nameEditor = name as EditText
15 |
16 | init {
17 | init()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/viewholder/MetricTemplateViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates.viewholder
2 |
3 | import android.view.View
4 | import com.supercilex.robotscouter.core.data.model.updateName
5 | import com.supercilex.robotscouter.core.model.Metric
6 |
7 | internal interface MetricTemplateViewHolder, T> : TemplateViewHolder {
8 | var metric: M
9 |
10 | override fun onFocusChange(v: View, hasFocus: Boolean) {
11 | // Only save data when user is leaving metric
12 | if (!hasFocus && v === nameEditor) {
13 | metric.updateName(nameEditor.text.toString())
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/feature/templates/src/main/java/com/supercilex/robotscouter/feature/templates/viewholder/TemplateViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.templates.viewholder
2 |
3 | import android.view.MotionEvent
4 | import android.view.View
5 | import android.widget.EditText
6 | import androidx.recyclerview.widget.ItemTouchHelper
7 | import androidx.recyclerview.widget.RecyclerView
8 |
9 | internal interface TemplateViewHolder : View.OnFocusChangeListener {
10 | val reorderView: View
11 | val nameEditor: EditText
12 |
13 | fun init() {
14 | nameEditor.onFocusChangeListener = this
15 | }
16 |
17 | fun requestFocus() {
18 | nameEditor.requestFocus()
19 | }
20 |
21 | fun enableDragToReorder(
22 | viewHolder: RecyclerView.ViewHolder,
23 | helper: ItemTouchHelper
24 | ) = reorderView.setOnTouchListener(View.OnTouchListener { v, event ->
25 | if (event.action == MotionEvent.ACTION_DOWN) {
26 | viewHolder.itemView.clearFocus() // Saves data
27 | helper.startDrag(viewHolder)
28 | v.performClick()
29 | return@OnTouchListener true
30 | }
31 | false
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_default_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 | -
11 |
12 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_delete_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_header_spinner.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_metric_checkbox.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_metric_counter.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_metric_header.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_metric_notes.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_metric_stopwatch.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_reorder_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/drawable/ic_ruler_grey_96dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/fragment_template_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/fragment_template_metric_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/scout_template_base_reorder.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/scout_template_checkbox.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/scout_template_counter.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/scout_template_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/layout/scout_template_stopwatch.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/menu/template_list_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/menu/template_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/feature/templates/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/feature/trash/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | implementation(project(":app:android-base"))
3 | implementation(project(":library:shared"))
4 | }
5 |
--------------------------------------------------------------------------------
/feature/trash/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/feature/trash/src/main/java/com/supercilex/robotscouter/feature/trash/SelectableScrollView.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.trash
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.MotionEvent
6 | import androidx.core.widget.NestedScrollView
7 |
8 | internal class SelectableScrollView : NestedScrollView {
9 | constructor(context: Context) : super(context)
10 |
11 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
12 |
13 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
14 | super(context, attrs, defStyleAttr)
15 |
16 | override fun onInterceptTouchEvent(ev: MotionEvent) = false
17 | }
18 |
--------------------------------------------------------------------------------
/feature/trash/src/main/java/com/supercilex/robotscouter/feature/trash/TrashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.trash
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import androidx.fragment.app.commit
6 | import com.supercilex.robotscouter.Bridge
7 | import com.supercilex.robotscouter.TrashActivityCompanion
8 | import com.supercilex.robotscouter.core.RobotScouter
9 | import com.supercilex.robotscouter.core.ui.ActivityBase
10 | import com.supercilex.robotscouter.R as RC
11 |
12 | @Bridge
13 | internal class TrashActivity : ActivityBase() {
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | setTheme(RC.style.RobotScouter_NoActionBar)
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_trash)
18 | if (savedInstanceState == null) {
19 | supportFragmentManager.commit {
20 | add(R.id.trash, TrashFragment.newInstance(), TrashFragment.TAG)
21 | }
22 | }
23 | }
24 |
25 | companion object : TrashActivityCompanion {
26 | override fun createIntent(): Intent = Intent(RobotScouter, TrashActivity::class.java)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/feature/trash/src/main/java/com/supercilex/robotscouter/feature/trash/TrashListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.feature.trash
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.selection.SelectionTracker
6 | import androidx.recyclerview.widget.DiffUtil
7 | import androidx.recyclerview.widget.ListAdapter
8 | import com.supercilex.robotscouter.core.LateinitVal
9 |
10 | internal class TrashListAdapter : ListAdapter(differ) {
11 | var selectionTracker: SelectionTracker by LateinitVal()
12 |
13 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = TrashViewHolder(
14 | LayoutInflater.from(parent.context).inflate(R.layout.trash_item, parent, false)
15 | )
16 |
17 | override fun onBindViewHolder(holder: TrashViewHolder, position: Int) {
18 | val trash = getItem(position)
19 | holder.bind(trash, selectionTracker.isSelected(trash.id))
20 | }
21 |
22 | public override fun getItem(position: Int): Trash = super.getItem(position)
23 |
24 | private companion object {
25 | val differ = object : DiffUtil.ItemCallback() {
26 | override fun areItemsTheSame(oldItem: Trash, newItem: Trash) = oldItem.id == newItem.id
27 |
28 | override fun areContentsTheSame(oldItem: Trash, newItem: Trash) = oldItem == newItem
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/drawable/ic_close_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/drawable/ic_delete_empty_96dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/drawable/ic_restore_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/drawable/trash_item_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/drawable/trash_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/layout/activity_trash.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/layout/trash_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/feature/trash/src/main/res/menu/trash_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4g -XX:ReservedCodeCacheSize=500m -Dfile.encoding=UTF-8
2 | org.gradle.parallel=true
3 | org.gradle.caching=true
4 | android.useAndroidX=true
5 | android.enableJetifier=true
6 | android.enableR8=false
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/library/common/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("org.jetbrains.kotlin.multiplatform")
3 | }
4 |
5 | kotlin {
6 | jvm("android")
7 |
8 | js("server") {
9 | useCommonJs()
10 | nodejs()
11 | }
12 |
13 | sourceSets {
14 | named("commonMain") {
15 | dependencies {
16 | implementation(Config.Libs.Kotlin.common)
17 | }
18 | }
19 |
20 | named("androidMain") {
21 | dependencies {
22 | implementation(Config.Libs.Kotlin.jvm)
23 | }
24 | }
25 |
26 | named("serverMain") {
27 | dependencies {
28 | implementation(Config.Libs.Kotlin.js)
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/library/common/src/commonMain/kotlin/com/supercilex/robotscouter/common/Collections.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.common
2 |
3 | val Iterable<*>.isSingleton: Boolean
4 | get() = iterator().let {
5 | if (!it.hasNext()) return false
6 | it.next()
7 | return !it.hasNext()
8 | }
9 |
10 | val Iterable<*>.isPolynomial: Boolean
11 | get() = iterator().let {
12 | return if (!it.hasNext()) false else !isSingleton
13 | }
14 |
15 | fun Array.second(): T {
16 | if (size < 2) throw NoSuchElementException("List has less than 2 elements.")
17 | return this[1]
18 | }
19 |
20 | fun List.second(): T {
21 | if (size < 2) throw NoSuchElementException("List has less than 2 elements.")
22 | return this[1]
23 | }
24 |
--------------------------------------------------------------------------------
/library/core-data/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.internal.CacheImplementation
2 |
3 | androidExtensions {
4 | defaultCacheImplementation = CacheImplementation.NONE
5 | }
6 |
7 | dependencies {
8 | api(project(":library:core"))
9 | api(project(":library:core-model"))
10 |
11 | api(Config.Libs.Firebase.firestore)
12 | api(Config.Libs.Firebase.auth)
13 | api(Config.Libs.Firebase.indexing)
14 |
15 | Config.Libs.Jetpack.lifecycle.forEach { api(it) }
16 |
17 | implementation(Config.Libs.Jetpack.appCompat) { isTransitive = false }
18 | implementation(Config.Libs.Jetpack.pref)
19 | implementation(Config.Libs.Misc.glide) { isTransitive = false }
20 |
21 | implementation(Config.Libs.PlayServices.auth) { isTransitive = false }
22 | implementation(Config.Libs.FirebaseUi.firestore) { exclude(module = "recyclerview-v7") }
23 | implementation(Config.Libs.Firebase.functions)
24 | implementation(Config.Libs.Firebase.storage)
25 | implementation(Config.Libs.Firebase.messaging)
26 | implementation(Config.Libs.Firebase.config)
27 | Config.Libs.Jetpack.work.forEach { implementation(it) }
28 |
29 | implementation(Config.Libs.Misc.retrofit)
30 | implementation(Config.Libs.Misc.retrofitGson)
31 | }
32 |
--------------------------------------------------------------------------------
/library/core-data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/Cleanup.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data
2 |
3 | import com.bumptech.glide.Glide
4 | import com.google.firebase.appindexing.FirebaseAppIndex
5 | import com.google.firebase.functions.ktx.functions
6 | import com.google.firebase.ktx.Firebase
7 | import com.supercilex.robotscouter.core.RobotScouter
8 | import kotlinx.coroutines.Dispatchers
9 | import kotlinx.coroutines.GlobalScope
10 | import kotlinx.coroutines.invoke
11 | import kotlinx.coroutines.launch
12 |
13 | fun cleanup() {
14 | GlobalScope.launch {
15 | Dispatchers.IO { Glide.get(RobotScouter).clearDiskCache() }
16 | cleanupJobs()
17 | }
18 | FirebaseAppIndex.getInstance().removeAll().logFailures("cleanup")
19 | }
20 |
21 | fun emptyTrash(ids: List? = null) = Firebase.functions
22 | .getHttpsCallable("clientApi")
23 | .call(mapOf("operation" to "empty-trash", "ids" to ids))
24 | .logFailures("emptyTrash", ids)
25 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/Io.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data
2 |
3 | import android.webkit.MimeTypeMap
4 | import java.io.File
5 |
6 | /** @return this directory after ensuring that it either already exists or was created */
7 | fun File.safeMkdirs(): File = apply {
8 | val create = { exists() || mkdirs() }
9 | check(create() || create()) { "Unable to create $this" }
10 | }
11 |
12 | /** @return this file after ensuring that it either already exists or was created */
13 | fun File.safeCreateNewFile(): File = apply {
14 | parentFile?.safeMkdirs()
15 |
16 | val create = { exists() || createNewFile() }
17 | check(create() || create()) { "Unable to create $this" }
18 | }
19 |
20 | fun File.mimeType(): String {
21 | return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: "*/*"
22 | }
23 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/Jobs.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data
2 |
3 | import androidx.work.WorkManager
4 | import androidx.work.await
5 | import com.supercilex.robotscouter.core.RobotScouter
6 | import com.supercilex.robotscouter.core.data.client.TEAM_MEDIA_UPLOAD
7 |
8 | internal suspend fun cleanupJobs() {
9 | WorkManager.getInstance(RobotScouter).apply {
10 | listOf(TEAM_MEDIA_UPLOAD)
11 | .map { cancelAllWorkByTag(it) }
12 | .forEach { it.result.await() }
13 | pruneWork()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/SimpleViewModelBase.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 |
5 | abstract class SimpleViewModelBase(state: SavedStateHandle) : ViewModelBase(state) {
6 | fun init() = init(null)
7 |
8 | final override fun onCreate(args: Unit?) = onCreate()
9 |
10 | open fun onCreate() = Unit
11 | }
12 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/TaskLogging.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data
2 |
3 | import com.google.android.gms.tasks.Task
4 | import com.google.firebase.firestore.DocumentReference
5 | import com.supercilex.robotscouter.core.CrashLogger
6 | import com.supercilex.robotscouter.core.logBreadcrumb
7 |
8 | fun Task.logFailures(
9 | tag: String,
10 | vararg hints: Any?
11 | ): Task = addOnFailureListener {
12 | for (hint in hints) logBreadcrumb(hint.toString())
13 | logBreadcrumb("Source: $tag")
14 | CrashLogger.invoke(it)
15 | }
16 |
17 | fun Task.logFailures(
18 | tag: String,
19 | ref: DocumentReference,
20 | vararg hints: Any?
21 | ) = logFailures(tag, "Path: ${ref.path}", *hints)
22 |
23 | fun Task.logFailures(
24 | tag: String,
25 | refs: List,
26 | vararg hints: Any?
27 | ) = logFailures(tag, "Paths: ${refs.joinToString { it.path }}", *hints)
28 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/ViewModelBase.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data
2 |
3 | import androidx.annotation.CallSuper
4 | import androidx.lifecycle.SavedStateHandle
5 | import androidx.lifecycle.ViewModel
6 | import java.util.concurrent.atomic.AtomicBoolean
7 |
8 | abstract class ViewModelBase(protected val state: SavedStateHandle) : ViewModel() {
9 | private val isInitialized = AtomicBoolean()
10 |
11 | fun init(args: T) {
12 | if (isInitialized.compareAndSet(false, true)) {
13 | onCreate(args)
14 | }
15 | }
16 |
17 | protected abstract fun onCreate(args: T)
18 |
19 | @CallSuper
20 | override fun onCleared() {
21 | isInitialized.set(false)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/client/WorkerBase.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data.client
2 |
3 | import android.content.Context
4 | import androidx.work.CoroutineWorker
5 | import androidx.work.WorkerParameters
6 | import com.supercilex.robotscouter.core.logBreadcrumb
7 | import kotlinx.coroutines.Dispatchers
8 | import kotlinx.coroutines.invoke
9 |
10 | internal abstract class WorkerBase(
11 | context: Context,
12 | workerParams: WorkerParameters
13 | ) : CoroutineWorker(context, workerParams) {
14 | override suspend fun doWork(): Result {
15 | if (runAttemptCount >= MAX_RUN_ATTEMPTS) return Result.failure()
16 |
17 | return try {
18 | Dispatchers.IO { doBlockingWork() }
19 | } catch (e: Exception) {
20 | logBreadcrumb("$javaClass errored: $e")
21 | Result.retry()
22 | }
23 | }
24 |
25 | protected abstract suspend fun doBlockingWork(): Result
26 |
27 | private companion object {
28 | const val MAX_RUN_ATTEMPTS = 7
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/model/ScoutsHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data.model
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import com.supercilex.robotscouter.core.data.LifecycleAwareFirestoreArray
5 | import com.supercilex.robotscouter.core.data.QueryGenerator
6 | import com.supercilex.robotscouter.core.data.ViewModelBase
7 | import com.supercilex.robotscouter.core.model.Scout
8 |
9 | class ScoutsHolder(state: SavedStateHandle) : ViewModelBase(state) {
10 | lateinit var scouts: LifecycleAwareFirestoreArray
11 | private set
12 |
13 | override fun onCreate(args: QueryGenerator) {
14 | scouts = LifecycleAwareFirestoreArray(args, scoutParser)
15 | scouts.keepAlive = true
16 | }
17 |
18 | public override fun onCleared() {
19 | super.onCleared()
20 | scouts.keepAlive = false
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/model/TeamCache.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data.model
2 |
3 | import com.supercilex.robotscouter.core.model.Team
4 | import java.util.Collections
5 |
6 | open class TeamCache(teams: Collection) {
7 | val teams: List by lazy {
8 | Collections.unmodifiableList(teams.sorted())
9 | }
10 | val teamNames: String by lazy { this.teams.getNames() }
11 | }
12 |
--------------------------------------------------------------------------------
/library/core-data/src/main/java/com/supercilex/robotscouter/core/data/remote/TeamMediaApi.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.data.remote
2 |
3 | import com.google.gson.JsonObject
4 | import okhttp3.RequestBody
5 | import retrofit2.Retrofit
6 | import retrofit2.converter.gson.GsonConverterFactory
7 | import retrofit2.http.Body
8 | import retrofit2.http.Header
9 | import retrofit2.http.POST
10 | import retrofit2.http.Query
11 |
12 | internal interface TeamMediaApi {
13 | @POST("image")
14 | suspend fun postToImgurAsync(
15 | @Header("Authorization") auth: String,
16 | @Query("title") title: String,
17 | @Body file: RequestBody
18 | ): JsonObject
19 |
20 | companion object {
21 | val IMGUR_RETROFIT: Retrofit = Retrofit.Builder()
22 | .baseUrl("https://api.imgur.com/3/")
23 | .addConverterFactory(GsonConverterFactory.create())
24 | .build()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/library/core-data/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Modèle %d
4 | Erreur dans la création du repérage:\nLe modèle que vous tentez d‘utiliser n’a pas encore été mis en cache. Veuillez ajouter au moins un repérage pendant que vous avez une connexion Internet pour que votre modèle puisse être mis en cache et utilisé hors ligne.
5 |
6 |
7 | Exportation en tableur
8 | Exportations complétées
9 | Affiche une notification actionnable pour gérer l\'exportation complétée.
10 | Exportations en cours
11 | Affiche le statut d\'une exportation en cours.
12 |
13 |
--------------------------------------------------------------------------------
/library/core-data/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Template %d
4 |
5 | Error adding new scout:\nThe template you are attempting to use hasn’t been cached yet.
6 | Please add at least one scout while you have an internet connection so your template may be
7 | cached for offline use.
8 |
9 |
10 |
11 | Spreadsheet exporting
12 | Completed exports
13 |
14 | Displays an actionable notification to manage the completed export.
15 |
16 | In-progress exports
17 | Displays the status of an in-progress export.
18 |
19 |
--------------------------------------------------------------------------------
/library/core-data/src/main/res/xml-v29/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/library/core-data/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/core-data/src/main/res/xml/remote_config_defaults.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | minimum_app_version
5 | -1
6 |
7 |
8 |
9 | show_rating_dialog
10 | true
11 |
12 |
13 |
14 | enable_auto_scout
15 | false
16 |
17 |
18 |
--------------------------------------------------------------------------------
/library/core-model/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.internal.CacheImplementation
2 |
3 | androidExtensions {
4 | defaultCacheImplementation = CacheImplementation.NONE
5 | }
6 |
7 | dependencies {
8 | implementation(project(":library:common"))
9 | implementation(Config.Libs.Jetpack.core)
10 |
11 | compileOnly(Config.Libs.Firebase.firestore) { exclude(group = "com.google.guava") }
12 | compileOnly(Config.Libs.Misc.gson)
13 | }
14 |
--------------------------------------------------------------------------------
/library/core-model/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/core-model/src/main/java/com/supercilex/robotscouter/core/model/MetricType.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.model
2 |
3 | import java.util.Collections
4 |
5 | enum class MetricType(val id: Int) {
6 | HEADER(5),
7 | BOOLEAN(0),
8 | NUMBER(1),
9 | STOPWATCH(4),
10 | TEXT(3),
11 | LIST(2);
12 |
13 | companion object {
14 | /**
15 | * Identical to the native values() method except that this one returns an immutable [List]
16 | * instead of an [Array] which must be copied defensively.
17 | *
18 | * @see enumValues
19 | */
20 | val values: List = Collections.unmodifiableList(values().toList())
21 |
22 | fun valueOf(id: Int): MetricType = requireNotNull(values.find { it.id == id }) {
23 | "Unknown metric type: $id"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/library/core-model/src/main/java/com/supercilex/robotscouter/core/model/OrderedModel.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.model
2 |
3 | interface OrderedModel {
4 | var position: Int
5 | }
6 |
--------------------------------------------------------------------------------
/library/core-model/src/main/java/com/supercilex/robotscouter/core/model/OrderedRemoteModel.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.model
2 |
3 | import androidx.annotation.Keep
4 | import com.google.firebase.firestore.DocumentReference
5 | import com.google.firebase.firestore.Exclude
6 |
7 | interface OrderedRemoteModel : OrderedModel {
8 | @get:Keep
9 | override var position: Int
10 |
11 | @get:Exclude
12 | val ref: DocumentReference
13 | }
14 |
--------------------------------------------------------------------------------
/library/core-model/src/main/java/com/supercilex/robotscouter/core/model/Scout.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.model
2 |
3 | import androidx.annotation.Keep
4 | import com.google.firebase.Timestamp
5 | import com.google.firebase.firestore.Exclude
6 |
7 | data class Scout(
8 | @Exclude
9 | @get:Exclude
10 | val id: String,
11 |
12 | @Exclude
13 | @get:Keep
14 | val templateId: String,
15 |
16 | @Exclude
17 | @get:Keep
18 | val name: String? = null,
19 |
20 | @Exclude
21 | @get:Keep
22 | val timestamp: Timestamp = Timestamp.now(),
23 |
24 | @Exclude
25 | @get:Exclude
26 | val metrics: List> = emptyList()
27 | )
28 |
--------------------------------------------------------------------------------
/library/core-model/src/main/java/com/supercilex/robotscouter/core/model/TemplateType.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.model
2 |
3 | import androidx.core.text.isDigitsOnly
4 | import java.util.Collections
5 |
6 | enum class TemplateType(val id: Int) {
7 | MATCH(0),
8 | PIT(1),
9 | EMPTY(2);
10 |
11 | companion object {
12 | val DEFAULT: TemplateType = MATCH
13 | /**
14 | * Identical to the native values() method except that this one returns an immutable [List]
15 | * instead of an [Array] which must be copied defensively.
16 | *
17 | * @see enumValues
18 | */
19 | val values: List = Collections.unmodifiableList(values().toList())
20 |
21 | fun valueOf(id: Int): TemplateType = requireNotNull(coerce(id.toString())) {
22 | "Unknown template type: $id"
23 | }
24 |
25 | fun coerce(id: String?): TemplateType? = if (id?.isDigitsOnly() == true) {
26 | values.find { it.id == id.toInt() }
27 | } else {
28 | null
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library/core-ui/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.internal.CacheImplementation
2 |
3 | android {
4 | buildTypes {
5 | named("release") {
6 | postprocessing {
7 | consumerProguardFile("proguard-rules.pro")
8 | }
9 | }
10 | }
11 | }
12 |
13 | androidExtensions {
14 | defaultCacheImplementation = CacheImplementation.NONE
15 | }
16 |
17 | dependencies {
18 | api(project(":library:core"))
19 |
20 | api(Config.Libs.Jetpack.lifecycle.first())
21 | api(Config.Libs.Jetpack.fragment)
22 | api(Config.Libs.Jetpack.material)
23 | api(Config.Libs.Jetpack.emoji)
24 | api(Config.Libs.Jetpack.constraint)
25 | api(Config.Libs.FirebaseUi.firestore)
26 | api(Config.Libs.Jetpack.rv)
27 | api(Config.Libs.Jetpack.rvSelection)
28 |
29 | implementation(Config.Libs.Jetpack.browser)
30 | implementation(Config.Libs.Jetpack.pref)
31 | implementation(Config.Libs.Misc.permissions)
32 | implementation(Config.Libs.Misc.flexbox)
33 | }
34 |
--------------------------------------------------------------------------------
/library/core-ui/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keepnames class * extends com.supercilex.robotscouter.core.ui.FragmentBase
2 | -keepnames class * extends com.supercilex.robotscouter.core.ui.DialogFragmentBase
3 | -keepnames class * extends com.supercilex.robotscouter.core.ui.BottomSheetDialogFragmentBase
4 | -keepnames class * extends com.supercilex.robotscouter.core.ui.PreferenceFragmentBase
5 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/java/com/supercilex/robotscouter/core/ui/Flow.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.ui
2 |
3 | import android.content.Intent
4 | import android.os.Build
5 | import androidx.recyclerview.widget.RecyclerView
6 |
7 | fun Intent.addNewDocumentFlags(): Intent {
8 | if (Build.VERSION.SDK_INT >= 21) {
9 | addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
10 | } else {
11 | @Suppress("DEPRECATION")
12 | addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
13 | }
14 | addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
15 | return this
16 | }
17 |
18 | interface RecyclerPoolHolder {
19 | val recyclerPool: RecyclerView.RecycledViewPool
20 | }
21 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/java/com/supercilex/robotscouter/core/ui/StateHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.ui
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 |
6 | class StateHolder(state: T) {
7 | private val _liveData = MutableLiveData(state)
8 | val liveData: LiveData get() = _liveData
9 |
10 | private var _value: T = state
11 | val value: T get() = _value
12 |
13 | fun update(notify: Boolean = true, block: T.() -> T) {
14 | synchronized(LOCK) {
15 | _value = block(value)
16 | if (notify) _liveData.postValue(value)
17 | }
18 | }
19 |
20 | private companion object {
21 | val LOCK = Object()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/java/com/supercilex/robotscouter/core/ui/views/CardMetricFlexboxLayout.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.ui.views
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.util.AttributeSet
6 | import com.google.android.flexbox.FlexboxLayout
7 | import com.supercilex.robotscouter.core.ui.CardMetric
8 | import com.supercilex.robotscouter.core.ui.CardMetricHelper
9 |
10 | class CardMetricFlexboxLayout : FlexboxLayout, CardMetric {
11 | override val helper = CardMetricHelper(this)
12 |
13 | constructor(context: Context) : super(context)
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
16 |
17 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
18 | super(context, attrs, defStyleAttr)
19 |
20 | init {
21 | helper.init()
22 | }
23 |
24 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
25 | super.onLayout(changed, left, top, right, bottom)
26 | super.onLayout(changed, left, top, right, bottom)
27 | }
28 |
29 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) =
30 | super.onSizeChanged(w, h, oldw, oldh)
31 |
32 | override fun onDraw(canvas: Canvas) {
33 | super.onDraw(canvas)
34 | super.onDraw(canvas)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/java/com/supercilex/robotscouter/core/ui/views/CardMetricLinearLayout.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.ui.views
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.util.AttributeSet
6 | import android.widget.LinearLayout
7 | import com.supercilex.robotscouter.core.ui.CardMetric
8 | import com.supercilex.robotscouter.core.ui.CardMetricHelper
9 |
10 | class CardMetricLinearLayout : LinearLayout, CardMetric {
11 | override val helper = CardMetricHelper(this)
12 |
13 | constructor(context: Context) : super(context)
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
16 |
17 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
18 | super(context, attrs, defStyleAttr)
19 |
20 | init {
21 | helper.init()
22 | }
23 |
24 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
25 | super.onLayout(changed, left, top, right, bottom)
26 | super.onLayout(changed, left, top, right, bottom)
27 | }
28 |
29 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) =
30 | super.onSizeChanged(w, h, oldw, oldh)
31 |
32 | override fun onDraw(canvas: Canvas) {
33 | super.onDraw(canvas)
34 | super.onDraw(canvas)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/java/com/supercilex/robotscouter/core/ui/views/SupportVectorDrawablesImageButton.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.ui.views
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import androidx.appcompat.widget.AppCompatImageButton
6 | import androidx.core.content.withStyledAttributes
7 | import com.supercilex.robotscouter.core.ui.R
8 | import com.supercilex.robotscouter.core.ui.getDrawableCompat
9 | import com.supercilex.robotscouter.core.ui.getIconThemedContext
10 |
11 | /** Supports custom icon styling. */
12 | open class SupportVectorDrawablesImageButton : AppCompatImageButton {
13 | constructor(context: Context) : super(context)
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
16 | applyDrawable(attrs)
17 | }
18 |
19 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
20 | super(context, attrs, defStyleAttr) {
21 | applyDrawable(attrs)
22 | }
23 |
24 | private fun applyDrawable(set: AttributeSet) {
25 | context.withStyledAttributes(set, R.styleable.Icon) {
26 | setImageDrawable(getIconThemedContext(context).getDrawableCompat(
27 | getResourceId(R.styleable.Icon_iconDrawable, -1)
28 | ))
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/java/com/supercilex/robotscouter/core/ui/views/UnscrollableViewPager.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core.ui.views
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.util.AttributeSet
6 | import android.view.MotionEvent
7 | import androidx.viewpager.widget.ViewPager
8 |
9 | /**
10 | * [ViewPager] that prevents horizontal scrolling.
11 | */
12 | class UnscrollableViewPager : ViewPager {
13 | constructor(context: Context) : super(context)
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
16 |
17 | @SuppressLint("ClickableViewAccessibility") // We purposefully don't want to allow swiping
18 | override fun onTouchEvent(event: MotionEvent) = false
19 |
20 | override fun onInterceptTouchEvent(event: MotionEvent) = false
21 | }
22 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/color/enablable_button_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/color/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable-anydpi-v23/launch_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable-hdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/library/core-ui/src/main/res/drawable-hdpi/ic_logo.png
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable-xhdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/library/core-ui/src/main/res/drawable-xhdpi/ic_logo.png
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable-xxhdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/library/core-ui/src/main/res/drawable-xxhdpi/ic_logo.png
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable-xxxhdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/library/core-ui/src/main/res/drawable-xxxhdpi/ic_logo.png
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable/card_item_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/library/core-ui/src/main/res/drawable/ic_logo.png
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/drawable/launch_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | -
10 |
14 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Oui
4 | Non
5 | Sauvegarder
6 | Annuler
7 |
8 | Partager
9 | Ouvrir
10 | Supprimer
11 | Supprimé
12 | Annulé
13 |
14 | Aucune connexion Internet
15 | Connexion requise
16 | Connexion réussie !
17 | Échec de la connexion
18 | Une erreur inconnue s\'est produite
19 |
20 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-large-port/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @dimen/spacing_large_medium
4 | @dimen/spacing_large
5 |
6 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-large/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @dimen/spacing_normal
4 | @dimen/spacing_normal
5 | @dimen/spacing_xlarge
6 | @dimen/spacing_large
7 | @dimen/spacing_xlarge
8 | @dimen/spacing_large
9 |
10 | 600dp
11 |
12 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-night-v27/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @android:color/white
4 | @color/material_grey_300
5 |
6 | #757575
7 | #BDBDBD
8 | @color/material_grey_700
9 | @color/material_grey_600
10 | #46264CAC
11 | #dc111111
12 |
13 |
14 | #3A3A3A
15 |
16 | @color/material_grey_800
17 |
18 | #EEEEEE
19 |
20 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-normal-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @dimen/spacing_xlarge
4 | @dimen/spacing_large
5 |
6 | 600dp
7 |
8 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
12 |
13 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-v27/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-xlarge-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @dimen/spacing_large_medium
4 | @dimen/spacing_large
5 | @dimen/spacing_xxlarge
6 | @dimen/spacing_large
7 | @dimen/spacing_xlarge
8 | @dimen/spacing_large
9 |
10 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values-xlarge-port/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @dimen/spacing_normal
4 | @dimen/spacing_normal
5 |
6 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/library/core-ui/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Yes
4 | No
5 | Save
6 | Undo
7 |
8 | Share
9 | Open
10 | Delete
11 | Deleted
12 | Cancelled
13 |
14 | No internet connection
15 | Sign in required
16 | Successfully signed in!
17 | Sign in failed
18 | An unknown error occurred
19 |
20 |
--------------------------------------------------------------------------------
/library/core/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.internal.CacheImplementation
2 |
3 | androidExtensions {
4 | defaultCacheImplementation = CacheImplementation.NONE
5 | }
6 |
7 | dependencies {
8 | api(project(":library:common"))
9 |
10 | api(Config.Libs.Kotlin.jvm)
11 | api(Config.Libs.Kotlin.coroutinesAndroid)
12 | api(Config.Libs.Kotlin.coroutinesTasks)
13 | api(Config.Libs.Firebase.analytics)
14 | api(Config.Libs.Firebase.crashlytics)
15 | api(Config.Libs.Jetpack.core)
16 |
17 | debugImplementation(Config.Libs.Misc.leakCanary)
18 | }
19 |
--------------------------------------------------------------------------------
/library/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/core/src/main/java/com/supercilex/robotscouter/core/Connectivity.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core
2 |
3 | import android.net.ConnectivityManager
4 | import androidx.core.content.getSystemService
5 |
6 | val isOnline get() = connectivityManager.activeNetworkInfo?.isConnected == true
7 |
8 | val isOffline get() = !isOnline
9 |
10 | private val connectivityManager by lazy {
11 | checkNotNull(RobotScouter.getSystemService())
12 | }
13 |
--------------------------------------------------------------------------------
/library/core/src/main/java/com/supercilex/robotscouter/core/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core
2 |
3 | import android.os.Build
4 | import android.os.Handler
5 | import android.os.Looper
6 | import android.provider.Settings
7 | import androidx.core.app.ActivityManagerCompat
8 | import androidx.core.content.getSystemService
9 |
10 | val mainHandler = Handler(Looper.getMainLooper())
11 | val Thread.isMain get() = this === mainHandler.looper.thread
12 |
13 | val fullVersionName: String by lazy {
14 | // Get it from the package manager instead of the BuildConfig to support injected version names
15 | // from the automated build system.
16 | RobotScouter.packageManager.getPackageInfo(RobotScouter.packageName, 0).versionName
17 | }
18 | val fullVersionCode by lazy {
19 | // See fullVersionName
20 | RobotScouter.packageManager.getPackageInfo(RobotScouter.packageName, 0).run {
21 | if (Build.VERSION.SDK_INT >= 28) {
22 | longVersionCode
23 | } else {
24 | @Suppress("DEPRECATION")
25 | versionCode.toLong()
26 | }
27 | }
28 | }
29 | val providerAuthority: String by lazy { "${RobotScouter.packageName}.provider" }
30 |
31 | val isLowRamDevice: Boolean by lazy {
32 | ActivityManagerCompat.isLowRamDevice(checkNotNull(RobotScouter.getSystemService()))
33 | }
34 | val isInTestMode: Boolean by lazy {
35 | Settings.System.getString(RobotScouter.contentResolver, "firebase.test.lab") == "true"
36 | }
37 |
--------------------------------------------------------------------------------
/library/core/src/main/java/com/supercilex/robotscouter/core/Properties.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core
2 |
3 | import kotlin.properties.ReadOnlyProperty
4 | import kotlin.properties.ReadWriteProperty
5 | import kotlin.reflect.KProperty
6 |
7 | fun unsafeLazy(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer)
8 |
9 | class LateinitVal : ReadWriteProperty {
10 | private var value: T? = null
11 |
12 | override fun getValue(thisRef: Any?, property: KProperty<*>): T = checkNotNull(value) {
13 | "Property ${property.name} should be initialized before get."
14 | }
15 |
16 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
17 | check(this.value == null) {
18 | "Property ${property.name} is a val and cannot change its value."
19 | }
20 | this.value = value
21 | }
22 | }
23 |
24 | class ValueSeeker(private val evaluator: () -> T) : ReadOnlyProperty {
25 | private var value: T? = null
26 |
27 | override fun getValue(thisRef: Any?, property: KProperty<*>) =
28 | value ?: synchronized(this) { value ?: evaluator().also { value = it } }
29 | }
30 |
--------------------------------------------------------------------------------
/library/core/src/main/java/com/supercilex/robotscouter/core/RobotScouter.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.core
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 |
6 | @Suppress("PropertyName")
7 | val RobotScouter
8 | get() = _globalContext
9 | @SuppressLint("StaticFieldLeak")
10 | @Suppress("ObjectPropertyName")
11 | lateinit var _globalContext: Context
12 |
--------------------------------------------------------------------------------
/library/core/src/main/java/com/supercilex/robotscouter/core/Toasts.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("NOTHING_TO_INLINE", "unused")
2 |
3 | package com.supercilex.robotscouter.core
4 |
5 | import android.widget.Toast
6 |
7 | /**
8 | * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration.
9 | *
10 | * @param message the message text resource.
11 | */
12 | inline fun toast(message: Int): Toast = Toast
13 | .makeText(RobotScouter, message, Toast.LENGTH_SHORT)
14 | .apply { show() }
15 |
16 | /**
17 | * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration.
18 | *
19 | * @param message the message text.
20 | */
21 | inline fun toast(message: CharSequence): Toast = Toast
22 | .makeText(RobotScouter, message, Toast.LENGTH_SHORT)
23 | .apply { show() }
24 |
25 | /**
26 | * Display the simple Toast message with the [Toast.LENGTH_LONG] duration.
27 | *
28 | * @param message the message text resource.
29 | */
30 | inline fun longToast(message: Int): Toast = Toast
31 | .makeText(RobotScouter, message, Toast.LENGTH_LONG)
32 | .apply { show() }
33 |
34 | /**
35 | * Display the simple Toast message with the [Toast.LENGTH_LONG] duration.
36 | *
37 | * @param message the message text.
38 | */
39 | inline fun longToast(message: CharSequence): Toast = Toast
40 | .makeText(RobotScouter, message, Toast.LENGTH_LONG)
41 | .apply { show() }
42 |
--------------------------------------------------------------------------------
/library/core/src/main/resources/META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler:
--------------------------------------------------------------------------------
1 | com.supercilex.robotscouter.core.LoggingHandler
2 |
--------------------------------------------------------------------------------
/library/shared-scouting/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | api(project(":library:shared"))
3 |
4 | implementation(Config.Libs.Jetpack.cardView)
5 | implementation(Config.Libs.Misc.snap)
6 | }
7 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/java/com/supercilex/robotscouter/shared/scouting/MetricListHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.shared.scouting
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import com.google.firebase.firestore.CollectionReference
5 | import com.supercilex.robotscouter.common.FIRESTORE_POSITION
6 | import com.supercilex.robotscouter.core.data.LifecycleAwareFirestoreArray
7 | import com.supercilex.robotscouter.core.data.ViewModelBase
8 | import com.supercilex.robotscouter.core.data.model.metricParser
9 | import com.supercilex.robotscouter.core.model.Metric
10 |
11 | class MetricListHolder(state: SavedStateHandle) : ViewModelBase(state) {
12 | lateinit var metrics: LifecycleAwareFirestoreArray>
13 | private set
14 |
15 | override fun onCreate(args: CollectionReference) {
16 | metrics = LifecycleAwareFirestoreArray({ args.orderBy(FIRESTORE_POSITION) }, metricParser)
17 | metrics.keepAlive = true
18 | }
19 |
20 | override fun onCleared() {
21 | super.onCleared()
22 | metrics.keepAlive = false
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/java/com/supercilex/robotscouter/shared/scouting/MetricViewHolderBase.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.shared.scouting
2 |
3 | import android.view.View
4 | import android.widget.TextView
5 | import androidx.annotation.CallSuper
6 | import androidx.fragment.app.FragmentManager
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.supercilex.robotscouter.core.model.Metric
9 | import kotlinx.android.extensions.LayoutContainer
10 | import java.lang.ref.WeakReference
11 |
12 | abstract class MetricViewHolderBase, T>(
13 | override val containerView: View
14 | ) : RecyclerView.ViewHolder(containerView), LayoutContainer {
15 | lateinit var metric: M
16 | private set
17 |
18 | protected val name: TextView = itemView.findViewById(R.id.name)
19 | private lateinit var _fragmentManager: WeakReference
20 | // This is safe b/c we're only using it to show dialogs. Anyways, we'll be getting rid of those.
21 | protected val fragmentManager get() = checkNotNull(_fragmentManager.get())
22 |
23 | fun bind(metric: M, manager: FragmentManager) {
24 | this.metric = metric
25 | this._fragmentManager = WeakReference(manager)
26 |
27 | bind()
28 | }
29 |
30 | @CallSuper
31 | protected open fun bind() {
32 | name.text = metric.name
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/java/com/supercilex/robotscouter/shared/scouting/viewholder/CheckboxViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.shared.scouting.viewholder
2 |
3 | import android.view.View
4 | import com.supercilex.robotscouter.core.data.model.update
5 | import com.supercilex.robotscouter.core.model.Metric
6 | import com.supercilex.robotscouter.shared.scouting.MetricViewHolderBase
7 | import com.supercilex.robotscouter.shared.scouting.R
8 | import kotlinx.android.synthetic.main.scout_base_checkbox.*
9 |
10 | open class CheckboxViewHolder(
11 | itemView: View
12 | ) : MetricViewHolderBase(itemView), View.OnClickListener {
13 | init {
14 | checkBox.setOnClickListener(this)
15 | name.setOnClickListener(this)
16 | }
17 |
18 | public override fun bind() {
19 | super.bind()
20 | checkBox.isChecked = metric.value
21 | checkBox.jumpDrawablesToCurrentState() // Skip animation on first load
22 | }
23 |
24 | override fun onClick(v: View) {
25 | if (v.id == R.id.checkBox) metric.update(checkBox.isChecked)
26 | if (v.id == R.id.name) checkBox.performClick()
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/java/com/supercilex/robotscouter/shared/scouting/viewholder/HeaderViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.shared.scouting.viewholder
2 |
3 | import android.view.View
4 | import androidx.core.view.updateLayoutParams
5 | import androidx.recyclerview.widget.RecyclerView
6 | import com.supercilex.robotscouter.core.model.Metric
7 | import com.supercilex.robotscouter.shared.scouting.MetricViewHolderBase
8 | import com.supercilex.robotscouter.core.ui.R as RC
9 |
10 | open class HeaderViewHolder(
11 | itemView: View
12 | ) : MetricViewHolderBase(itemView) {
13 | private val topMargin =
14 | itemView.resources.getDimensionPixelSize(RC.dimen.list_item_padding_vertical_within)
15 |
16 | override fun bind() {
17 | super.bind()
18 | itemView.updateLayoutParams {
19 | topMargin = if (layoutPosition == 0) 0 else this@HeaderViewHolder.topMargin
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/color/activatable_button_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/color/button_outline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/drawable-anydpi-v21/button_outline_colored.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 | -
12 |
13 |
14 |
15 |
18 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/drawable/button_outline_colored.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
16 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/drawable/ic_remove_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/drawable/ic_timer_off_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/drawable/ic_timer_on_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/layout/dialog_value.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/layout/scout_base_checkbox.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nom du repérage
4 | Chargement…\nVérifiez votre connexion Internet
5 |
6 |
7 | Modifier la valeur
8 | Valeur
9 | Incrémenter le compteur
10 | Décrémenter le compteur
11 |
12 |
13 | Démarrer
14 | Arrêter (%s)
15 | Cycle %d
16 | Moyenne
17 | Tour de chronomètre ajouté
18 |
19 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/values-v17/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/shared-scouting/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Scout name
4 | Loading…\nCheck your internet connection
5 |
6 |
7 | Edit value
8 | Value
9 | Increment counter
10 | Decrement counter
11 |
12 |
13 | Start
14 | Stop (%s)
15 | Cycle %d
16 | Average
17 | Added stopwatch lap
18 |
19 |
--------------------------------------------------------------------------------
/library/shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | api(project(":library:core-data"))
3 | api(project(":library:core-ui"))
4 |
5 | api(Config.Libs.FirebaseUi.auth)
6 | api(Config.Libs.PlayServices.auth)
7 | api(Config.Libs.Misc.glide)
8 |
9 | implementation(Config.Libs.FirebaseUi.facebook)
10 | implementation(Config.Libs.FirebaseUi.twitter) { isTransitive = true }
11 | implementation(Config.Libs.Firebase.links)
12 | }
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/java/com/supercilex/robotscouter/shared/SharedLifecycleResource.kt:
--------------------------------------------------------------------------------
1 | package com.supercilex.robotscouter.shared
2 |
3 | import androidx.lifecycle.ViewModel
4 | import java.util.concurrent.atomic.AtomicInteger
5 |
6 | /**
7 | * Manages lifecycle events for shared objects. Used to process fragment view lifecycle events for
8 | * activity scoped resources.
9 | */
10 | class SharedLifecycleResource : ViewModel() {
11 | private val counts = mutableMapOf, AtomicInteger>()
12 |
13 | fun onCreate(resource: Any) {
14 | counts.getOrPut(resource.javaClass) { AtomicInteger() }.incrementAndGet()
15 | }
16 |
17 | fun onDestroy(resource: T, cleanup: T.() -> Unit) {
18 | val count = counts.getValue(resource.javaClass).decrementAndGet()
19 | if (count == 0) cleanup(resource)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/anim/slide_in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/anim/slide_out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/color/empty_icon_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_add_a_photo_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_add_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_check_grey_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_content_paste_grey_96dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_delete_forever_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_info_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_launch_accent_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_mode_edit_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_person_grey_96dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_share_colorable_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/drawable/ic_star_accent_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/shared/src/main/res/layout/dialog_should_upload_media.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/secrets.tar.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SUPERCILEX/Robot-Scouter/8158790188cf0b9545f9b8ff80b0182f2eafd927/secrets.tar.enc
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `gradle-enterprise`
3 | }
4 |
5 | include(
6 | ":app:android-base", "app:server:functions",
7 |
8 | ":library:common",
9 | ":library:core", ":library:core-model", ":library:core-data", ":library:core-ui",
10 | ":library:shared", ":library:shared-scouting",
11 |
12 | ":feature:teams", ":feature:autoscout",
13 | ":feature:scouts", ":feature:templates",
14 | ":feature:exports",
15 | ":feature:trash", ":feature:settings"
16 | )
17 |
18 | rootProject.name = "Robot-Scouter"
19 |
--------------------------------------------------------------------------------