Showing preview only (338K chars total). Download the full file or copy to clipboard to get everything.
Repository: lswiderski/mi-scale-exporter
Branch: main
Commit: 1063bcb5e511
Files: 106
Total size: 308.8 KB
Directory structure:
gitextract_nz2lm8kb/
├── .gitignore
├── .idea/
│ ├── .idea.MiScaleExporter/
│ │ └── .idea/
│ │ ├── .name
│ │ ├── encodings.xml
│ │ ├── indexLayout.xml
│ │ ├── misc.xml
│ │ ├── projectSettingsUpdater.xml
│ │ └── vcs.xml
│ └── .idea.miscale2garmin/
│ └── .idea/
│ ├── .gitignore
│ ├── .name
│ ├── encodings.xml
│ ├── indexLayout.xml
│ ├── misc.xml
│ └── vcs.xml
├── LICENSE
├── MiScaleExporter.sln
├── README.md
├── docs/
│ ├── _config.yml
│ ├── _includes/
│ │ ├── head-custom-google-analytics.html
│ │ └── head-custom.html
│ ├── _layouts/
│ │ └── default.html
│ ├── _sass/
│ │ ├── cayman.scss
│ │ ├── jekyll-theme-cayman.scss
│ │ ├── normalize.scss
│ │ ├── rouge-github.scss
│ │ └── variables.scss
│ └── index.md
└── src/
└── MiScaleExporter.MAUI/
├── App.xaml
├── App.xaml.cs
├── AppShell.xaml
├── AppShell.xaml.cs
├── Behaviors/
│ ├── NumericDoubleValidationBehavior.cs
│ └── NumericIntValidationBehavior.cs
├── Controls/
│ ├── FlyoutFooter.xaml
│ ├── FlyoutFooter.xaml.cs
│ ├── FlyoutHeader.xaml
│ └── FlyoutHeader.xaml.cs
├── Converters/
│ └── InvertedBoolConverter.cs
├── MauiProgram.cs
├── MiScaleExporter.MAUI.csproj
├── Models/
│ ├── BodyComposition.cs
│ ├── GarminApiResponse.cs
│ ├── GarminBodyCompositionRequest.cs
│ ├── GarminExternalApiResponse.cs
│ ├── GarminFitFileCreationResult.cs
│ ├── GarminUploadResult.cs
│ ├── PreferencesKeys.cs
│ ├── ScaleMeasurement.cs
│ ├── ScaleType.cs
│ ├── SettingKeys.cs
│ ├── Sex.cs
│ └── User.cs
├── Permission/
│ ├── BluetoothConnectPermission.cs
│ └── IBluetoothConnectPermission.cs
├── Platforms/
│ ├── Android/
│ │ ├── AndroidManifest.xml
│ │ ├── MainActivity.cs
│ │ ├── MainApplication.cs
│ │ └── Resources/
│ │ └── values/
│ │ ├── colors.xml
│ │ └── styles.xml
│ ├── MacCatalyst/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── Tizen/
│ │ ├── Main.cs
│ │ └── tizen-manifest.xml
│ ├── Windows/
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── Package.appxmanifest
│ │ └── app.manifest
│ └── iOS/
│ ├── AppDelegate.cs
│ ├── Info.plist
│ └── Program.cs
├── Properties/
│ └── launchSettings.json
├── Resources/
│ ├── Fonts/
│ │ ├── FontAwesome6Regular.otf
│ │ └── FontAwesome6Solid.otf
│ ├── Localization/
│ │ ├── AppSnippets.Designer.cs
│ │ ├── AppSnippets.pl.resx
│ │ └── AppSnippets.resx
│ ├── Raw/
│ │ └── AboutAssets.txt
│ └── Styles/
│ ├── Colors.xaml
│ └── Styles.xaml
├── Services/
│ ├── DataInterpreter.cs
│ ├── GarminService.cs
│ ├── IDataInterpreter.cs
│ ├── IGarminService.cs
│ ├── ILogService.cs
│ ├── IScale.cs
│ ├── LogService.cs
│ └── Scale.cs
├── Utils/
│ └── DoubleValueParser.cs
├── ViewModels/
│ ├── AboutViewModel.cs
│ ├── BaseViewModel.cs
│ ├── FormViewModel.cs
│ ├── IFormViewModel.cs
│ ├── IScaleViewModel.cs
│ ├── ISettingsViewModel.cs
│ ├── ScaleViewModel.cs
│ └── SettingsViewModel.cs
└── Views/
├── AboutPage.xaml
├── AboutPage.xaml.cs
├── FormPage.xaml
├── FormPage.xaml.cs
├── HelpPage.xaml
├── HelpPage.xaml.cs
├── ScalePage.xaml
├── ScalePage.xaml.cs
├── SettingsPage.xaml
└── SettingsPage.xaml.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/rider,visualstudio,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=rider,visualstudio,visualstudiocode
### Rider ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
*.code-workspace
# Local History for Visual Studio Code
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
### VisualStudio Patch ###
# Additional files built by Visual Studio
# End of https://www.toptal.com/developers/gitignore/api/rider,visualstudio,visualstudiocode
================================================
FILE: .idea/.idea.MiScaleExporter/.idea/.name
================================================
MiScaleExporter
================================================
FILE: .idea/.idea.MiScaleExporter/.idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>
================================================
FILE: .idea/.idea.MiScaleExporter/.idea/indexLayout.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
================================================
FILE: .idea/.idea.MiScaleExporter/.idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="..\:/Projects/mi-scale-exporter/src/MiScaleExporter.Android/Resources/mipmap-anydpi-v26/icon.xml" value="0.5520833333333334" />
<entry key="..\:/Projects/mi-scale-exporter/src/MiScaleExporter.Android/Resources/mipmap-anydpi-v26/icon_round.xml" value="0.5520833333333334" />
</map>
</option>
</component>
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>
================================================
FILE: .idea/.idea.MiScaleExporter/.idea/projectSettingsUpdater.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderProjectSettingsUpdater">
<option name="vcsConfiguration" value="2" />
</component>
</project>
================================================
FILE: .idea/.idea.MiScaleExporter/.idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
================================================
FILE: .idea/.idea.miscale2garmin/.idea/.gitignore
================================================
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/.idea.miscale2garmin.iml
/.idea.MiScaleExporter.iml
/projectSettingsUpdater.xml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
================================================
FILE: .idea/.idea.miscale2garmin/.idea/.name
================================================
miscale2garmin
================================================
FILE: .idea/.idea.miscale2garmin/.idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>
================================================
FILE: .idea/.idea.miscale2garmin/.idea/indexLayout.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
================================================
FILE: .idea/.idea.miscale2garmin/.idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>
================================================
FILE: .idea/.idea.miscale2garmin/.idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: MiScaleExporter.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiScaleExporter.MAUI", "src\MiScaleExporter.MAUI\MiScaleExporter.MAUI.csproj", "{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|iPhone = Debug|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|Any CPU = Release|Any CPU
Release|iPhone = Release|iPhone
Release|iPhoneSimulator = Release|iPhoneSimulator
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|iPhone.Build.0 = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|iPhone.Deploy.0 = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|Any CPU.Build.0 = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|Any CPU.Deploy.0 = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|iPhone.ActiveCfg = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|iPhone.Build.0 = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|iPhone.Deploy.0 = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{39C1BB45-DB3C-4C1A-A3C0-5CBB35C753D0}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {44FCA853-2BA4-4001-945E-910A5CBFFEB1}
EndGlobalSection
EndGlobal
================================================
FILE: README.md
================================================
# mi-scale-exporter
Mobile App to export data from Mi Body Composition Scale (works with Mi Scale too) and upload it to Garmin Connect Cloud. It also allows you to upload manually entered body composition data to the Garmin cloud.
Instruction: [https://lswiderski.github.io/mi-scale-exporter/](https://lswiderski.github.io/mi-scale-exporter/)
Tested on Oneplus 5T (Android 10) and Mi Body Composition Scale (XMTZC02HM)
## Download
<a href="https://play.google.com/store/apps/details?id=com.lukaszswiderski.MiScaleExporter" target="_blank"><img alt="Google Play MiScale Exporter" height="90" src="https://play.google.com/intl/en_US/badges/images/generic/en_badge_web_generic.png"/></a>
- Google play: https://play.google.com/store/apps/details?id=com.lukaszswiderski.MiScaleExporter
- APK/AAB installers: https://github.com/lswiderski/mi-scale-exporter/releases
## iOS/iPadOS version
Check out this web project: https://github.com/lswiderski/WebBodyComposition
## Instruction
- Stand on your scale. Measure yourself. Complete the user form data, Scale Bluetooth address and get data from the scale. Mi Body Composition Scale is active up to 15 min after the measurement. (Bluetooth address can be found in Zepp Life > Profile > My devices > Mi Body Composition Scale > Bluetooth address (hold to copy)).
- If your scale supports "Weigh small object" - turn it off
- Then you can review your data and upload it to Garmin Cloud. If you do not have Mi scale and just want to manually insert the data, you can so.
- You can save the Garmin password in this App but you don't have to. Passwords Managers like KeePass2 works well too. If you do not provide a password in the settings, you will be asked for it each time before sending. No password will be saved in app.
- This app support 2FA/MFA codes (since v2.1.0)
- This App pass your data, email and password directly to Garmin Connect Cloud or you can change it to proxy API server and then it sends to Garmin Cloud.
- The Proxy API does not store or log anything, it's just a middleware between this App and Garmin services.
- Proxy API repository: https://github.com/lswiderski/yet-another-garmin-connect-client
- If you afraid of your data, you can host your own API server. Just change the server address in Settings. For now you can use default one: https://frog01-20364.wykr.es
## Diagram of the flow with Web Proxy
```mermaid
sequenceDiagram
participant Mobile App
participant Mi Body Composition Scale
participant API Endpoint Proxy
participant Garmin Cloud
Mobile App->>Mi Body Composition Scale: Connect and get data
Mi Body Composition Scale-->>Mobile App: Weight and Impedance data
loop
Mobile App->>Mobile App: Calculate Body Composition
end
Mobile App->>API Endpoint Proxy: Body Composition data
API Endpoint Proxy->>Garmin Cloud: Body Composition data
Garmin Cloud-->>API Endpoint Proxy: Result
API Endpoint Proxy-->>Mobile App: Result
```
## API Endpoint used in the app ([source](https://github.com/lswiderski/yet-another-garmin-connect-client))
```http
https://frog01-20364.wykr.es
```
## Diagram of the flow with direct send to Garmin Cloud
```mermaid
sequenceDiagram
participant Mobile App
participant Mi Body Composition Scale
participant Garmin Cloud
Mobile App->>Mi Body Composition Scale: Connect and get data
Mi Body Composition Scale-->>Mobile App: Weight and Impedance data
loop
Mobile App->>Mobile App: Calculate Body Composition
end
Mobile App->>Garmin Cloud: Body Composition data
Garmin Cloud-->>Mobile App: Result
```
## Stack
- MAUI & .NET 7 (C#)
- Autofac
- Plugin.BLE - To receive data via Bluetooth from Mi scale
- Xamarin.Essentials
- API Backend in C# (YAGCC project)
## Images
- Xiaomi settings (Bluetooth adress - Zepp Life)

- required user data

- settings

- measure

- Calculated body composition

- results in Garmin Cloud

## Inspiration
- https://github.com/RobertWojtowicz/miscale2garmin
- https://github.com/davidkroell/bodycomposition
## If you like my work, you can buy me a coffee
<a href="https://www.buymeacoffee.com/lukaszswiderski" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
================================================
FILE: docs/_config.yml
================================================
title: MiScale Exporter
description: Mobile App to export data from Mi Body Composition Scale and upload it to Garmin Connect Cloud
show_downloads: true
google_analytics:
theme: jekyll-theme-cayman
================================================
FILE: docs/_includes/head-custom-google-analytics.html
================================================
{% if site.google_analytics %}
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
(i[r] =
i[r] ||
function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
'script',
'//www.google-analytics.com/analytics.js',
'ga'
);
ga('create', '{{ site.google_analytics }}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}
================================================
FILE: docs/_includes/head-custom.html
================================================
<!-- start custom head snippets, customize with your own _includes/head-custom.html file -->
<!-- Setup Google Analytics -->
{% include head-custom-google-analytics.html %}
<!-- You can set your favicon here -->
<!-- link rel="shortcut icon" type="image/x-icon" href="{{ '/favicon.ico' | relative_url }}" -->
<!-- end custom head snippets -->
================================================
FILE: docs/_layouts/default.html
================================================
<!DOCTYPE html>
<html lang="{{ site.lang | default: "en-US" }}">
<head>
<meta charset="UTF-8">
{% seo %}
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700&display=swap" as="style" type="text/css" crossorigin>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#157878">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
{% include head-custom.html %}
</head>
<body>
<a id="skip-to-content" href="#content">Skip to the content.</a>
<header class="page-header" role="banner">
<h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1>
<h2 class="project-tagline">{{ page.description | default: site.description | default: site.github.project_tagline }}</h2>
{% if site.github.is_project_page %}
<a href="{{ site.github.repository_url }}" class="btn">View on GitHub</a>
{% endif %}
{% if site.show_downloads %}
<a href="https://play.google.com/store/apps/details?id=com.lukaszswiderski.MiScaleExporter" class="btn">Android</a>
<a href="https://web-body-composition.vercel.app/" class="btn">Web version (iOS)</a>
{% endif %}
</header>
<main id="content" class="main-content" role="main">
{{ content }}
<footer class="site-footer">
{% if site.github.is_project_page %}
<span class="site-footer-owner"><a href="{{ site.github.repository_url }}">{{ site.github.repository_name }}</a> is maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a>.</span>
{% endif %}
<span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a>.</span>
</footer>
</main>
</body>
</html>
================================================
FILE: docs/_sass/cayman.scss
================================================
// Placeholder file. If your site uses
// @import "{{ site.theme }}";
// Then using this theme with jekyll-remote-theme will work fine.
@import "jekyll-theme-cayman";
================================================
FILE: docs/_sass/jekyll-theme-cayman.scss
================================================
@import "normalize";
@import "rouge-github";
@import "variables";
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700&display=swap');
@mixin large {
@media screen and (min-width: #{$large-breakpoint}) {
@content;
}
}
@mixin medium {
@media screen and (min-width: #{$medium-breakpoint}) and (max-width: #{$large-breakpoint}) {
@content;
}
}
@mixin small {
@media screen and (max-width: #{$medium-breakpoint}) {
@content;
}
}
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
color: $body-text-color;
}
#skip-to-content {
height: 1px;
width: 1px;
position: absolute;
overflow: hidden;
top: -10px;
&:focus {
position: fixed;
top: 10px;
left: 10px;
height: auto;
width: auto;
background: invert($body-link-color);
outline: thick solid invert($body-link-color);
}
}
a {
color: $body-link-color;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
.btn {
display: inline-block;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.7);
background-color: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.2);
border-style: solid;
border-width: 1px;
border-radius: 0.3rem;
transition: color 0.2s, background-color 0.2s, border-color 0.2s;
&:hover {
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
background-color: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.3);
}
+ .btn {
margin-left: 1rem;
}
@include large {
padding: 0.75rem 1rem;
}
@include medium {
padding: 0.6rem 0.9rem;
font-size: 0.9rem;
}
@include small {
display: block;
width: 100%;
padding: 0.75rem;
font-size: 0.9rem;
+ .btn {
margin-top: 1rem;
margin-left: 0;
}
}
}
.page-header {
color: $header-heading-color;
text-align: center;
background-color: $header-bg-color;
background-image: linear-gradient(120deg, $header-bg-color-secondary, $header-bg-color);
@include large {
padding: 5rem 6rem;
}
@include medium {
padding: 3rem 4rem;
}
@include small {
padding: 2rem 1rem;
}
}
.project-name {
margin-top: 0;
margin-bottom: 0.1rem;
@include large {
font-size: 3.25rem;
}
@include medium {
font-size: 2.25rem;
}
@include small {
font-size: 1.75rem;
}
}
.project-tagline {
margin-bottom: 2rem;
font-weight: normal;
opacity: 0.7;
@include large {
font-size: 1.25rem;
}
@include medium {
font-size: 1.15rem;
}
@include small {
font-size: 1rem;
}
}
.main-content {
word-wrap: break-word;
:first-child {
margin-top: 0;
}
@include large {
max-width: 64rem;
padding: 2rem 6rem;
margin: 0 auto;
font-size: 1.1rem;
}
@include medium {
padding: 2rem 4rem;
font-size: 1.1rem;
}
@include small {
padding: 2rem 1rem;
font-size: 1rem;
}
kbd {
background-color: #fafbfc;
border: 1px solid #c6cbd1;
border-bottom-color: #959da5;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #959da5;
color: #444d56;
display: inline-block;
font-size: 11px;
line-height: 10px;
padding: 3px 5px;
vertical-align: middle;
}
img {
max-width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 2rem;
margin-bottom: 1rem;
font-weight: normal;
color: $section-headings-color;
}
p {
margin-bottom: 1em;
}
code {
padding: 2px 4px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 0.9rem;
color: $code-text-color;
background-color: $code-bg-color;
border-radius: 0.3rem;
}
pre {
padding: 0.8rem;
margin-top: 0;
margin-bottom: 1rem;
font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace;
color: $code-text-color;
word-wrap: normal;
background-color: $code-bg-color;
border: solid 1px $border-color;
border-radius: 0.3rem;
> code {
padding: 0;
margin: 0;
font-size: 0.9rem;
color: $code-text-color;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
}
.highlight {
margin-bottom: 1rem;
pre {
margin-bottom: 0;
word-break: normal;
}
}
.highlight pre,
pre {
padding: 0.8rem;
overflow: auto;
font-size: 0.9rem;
line-height: 1.45;
border-radius: 0.3rem;
-webkit-overflow-scrolling: touch;
}
pre code,
pre tt {
display: inline;
max-width: initial;
padding: 0;
margin: 0;
overflow: initial;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
&:before,
&:after {
content: normal;
}
}
ul,
ol {
margin-top: 0;
}
blockquote {
padding: 0 1rem;
margin-left: 0;
color: $blockquote-text-color;
border-left: 0.3rem solid $border-color;
> :first-child {
margin-top: 0;
}
> :last-child {
margin-bottom: 0;
}
}
table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all; // For Firefox to horizontally scroll wider tables.
-webkit-overflow-scrolling: touch;
th {
font-weight: bold;
}
th,
td {
padding: 0.5rem 1rem;
border: 1px solid $table-border-color;
}
}
dl {
padding: 0;
dt {
padding: 0;
margin-top: 1rem;
font-size: 1rem;
font-weight: bold;
}
dd {
padding: 0;
margin-bottom: 1rem;
}
}
hr {
height: 2px;
padding: 0;
margin: 1rem 0;
background-color: $hr-border-color;
border: 0;
}
}
.site-footer {
padding-top: 2rem;
margin-top: 2rem;
border-top: solid 1px $hr-border-color;
@include large {
font-size: 1rem;
}
@include medium {
font-size: 1rem;
}
@include small {
font-size: 0.9rem;
}
}
.site-footer-owner {
display: block;
font-weight: bold;
}
.site-footer-credits {
color: $blockquote-text-color;
}
================================================
FILE: docs/_sass/normalize.scss
================================================
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */ /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
================================================
FILE: docs/_sass/rouge-github.scss
================================================
.highlight table td { padding: 5px; }
.highlight table pre { margin: 0; }
.highlight .cm {
color: #999988;
font-style: italic;
}
.highlight .cp {
color: #999999;
font-weight: bold;
}
.highlight .c1 {
color: #999988;
font-style: italic;
}
.highlight .cs {
color: #999999;
font-weight: bold;
font-style: italic;
}
.highlight .c, .highlight .cd {
color: #999988;
font-style: italic;
}
.highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.highlight .gd {
color: #000000;
background-color: #ffdddd;
}
.highlight .ge {
color: #000000;
font-style: italic;
}
.highlight .gr {
color: #aa0000;
}
.highlight .gh {
color: #999999;
}
.highlight .gi {
color: #000000;
background-color: #ddffdd;
}
.highlight .go {
color: #888888;
}
.highlight .gp {
color: #555555;
}
.highlight .gs {
font-weight: bold;
}
.highlight .gu {
color: #aaaaaa;
}
.highlight .gt {
color: #aa0000;
}
.highlight .kc {
color: #000000;
font-weight: bold;
}
.highlight .kd {
color: #000000;
font-weight: bold;
}
.highlight .kn {
color: #000000;
font-weight: bold;
}
.highlight .kp {
color: #000000;
font-weight: bold;
}
.highlight .kr {
color: #000000;
font-weight: bold;
}
.highlight .kt {
color: #445588;
font-weight: bold;
}
.highlight .k, .highlight .kv {
color: #000000;
font-weight: bold;
}
.highlight .mf {
color: #009999;
}
.highlight .mh {
color: #009999;
}
.highlight .il {
color: #009999;
}
.highlight .mi {
color: #009999;
}
.highlight .mo {
color: #009999;
}
.highlight .m, .highlight .mb, .highlight .mx {
color: #009999;
}
.highlight .sb {
color: #d14;
}
.highlight .sc {
color: #d14;
}
.highlight .sd {
color: #d14;
}
.highlight .s2 {
color: #d14;
}
.highlight .se {
color: #d14;
}
.highlight .sh {
color: #d14;
}
.highlight .si {
color: #d14;
}
.highlight .sx {
color: #d14;
}
.highlight .sr {
color: #009926;
}
.highlight .s1 {
color: #d14;
}
.highlight .ss {
color: #990073;
}
.highlight .s {
color: #d14;
}
.highlight .na {
color: #008080;
}
.highlight .bp {
color: #999999;
}
.highlight .nb {
color: #0086B3;
}
.highlight .nc {
color: #445588;
font-weight: bold;
}
.highlight .no {
color: #008080;
}
.highlight .nd {
color: #3c5d5d;
font-weight: bold;
}
.highlight .ni {
color: #800080;
}
.highlight .ne {
color: #990000;
font-weight: bold;
}
.highlight .nf {
color: #990000;
font-weight: bold;
}
.highlight .nl {
color: #990000;
font-weight: bold;
}
.highlight .nn {
color: #555555;
}
.highlight .nt {
color: #000080;
}
.highlight .vc {
color: #008080;
}
.highlight .vg {
color: #008080;
}
.highlight .vi {
color: #008080;
}
.highlight .nv {
color: #008080;
}
.highlight .ow {
color: #000000;
font-weight: bold;
}
.highlight .o {
color: #000000;
font-weight: bold;
}
.highlight .w {
color: #bbbbbb;
}
.highlight {
background-color: #f8f8f8;
}
================================================
FILE: docs/_sass/variables.scss
================================================
// Breakpoints
$large-breakpoint: 64em !default;
$medium-breakpoint: 42em !default;
// Headers
$header-heading-color: #fff !default;
$header-bg-color: #159957 !default;
$header-bg-color-secondary: #155799 !default;
// Text
$section-headings-color: #159957 !default;
$body-text-color: #606c71 !default;
$body-link-color: #1e6bb8 !default;
$blockquote-text-color: #819198 !default;
// Code
$code-bg-color: #f3f6fa !default;
$code-text-color: #567482 !default;
// Borders
$border-color: #dce6f0 !default;
$table-border-color: #e9ebec !default;
$hr-border-color: #eff0f1 !default;
================================================
FILE: docs/index.md
================================================
---
layout: default
---
Mobile App to export data from Xiaomi Scales:
- Mi Smart Scale
- [Mi Body Composition Scale 1 and 2](#steps-to-connect-mi-body-compostion-scale-1-and-2)
- [Mi Body Composition Scale S400](#steps-to-connect-xiaomi-body-composition-scale-s400) (only Android)
and upload it to [Garmin Connect Cloud.](#garmin-connect-upload)
It also allows you to upload manually entered body composition data to the Garmin cloud.
> [!CAUTION]
> This application is not supported or endorsed by Xiaomi or Garmin. So it could stop working at any moment. It is intended for personal use only and is not to be used for financial gain. The creator takes no responsibility for any consequences that may arise from its use.
## If you like my work, you can buy me a coffee
<a href="https://www.buymeacoffee.com/lukaszswiderski" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
## Steps to Connect Mi Body Compostion Scale 1 and 2:
1. Add Scale to Zepp Life app.
2. You will need the Bluetooth address of the scale. Go to Zepp Life > Profile > My devices > Mi Body Composition Scale > Bluetooth address (hold to copy)
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/xiaomi.jpg"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/xiaomi.jpg" alt="Xiaomi settings" style="width: 400px; margin: auto;
display: block;"></a>
3. If your scale supports "Weigh small object" - turn it off
4. Open Settings in MiSCale Exporter. Select Scale Model to Mi Body Compositon Scale 1 / 2 and paste Bluetooth address.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/userdata.jpg"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/userdata.jpg" alt="MiScale Exporter settings" style="width: 400px; margin: auto; display: block;"></a>
5. Now it's time for measurement. Stand on your scale. Measure yourself and get data from the scale. Mi Body Composition Scale is active up to 15 min after the measurement.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/measure.jpg"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/measure.jpg" alt="measure" style="width: 400px; margin: auto;
display: block;"></a>
6. These types of scales do not measure body composition. They measure weight and impedance and estimate the result based on those measurements. The exact calculation algorithm is unknown, but with the help of reverse engineers, an approximate one has been achieved, which gives a satisfactory result. However, this means that the final result may differ slightly from that provided by the application. For this calculation proper age, height and sex is needed.
## Steps to Connect Xiaomi Body Composition Scale S400:
1. Add Scale to Xiaomi Home App and do first measurement. You can disable Heart rate measurement to fast up whole process.
2. You will need scale MAC address and BLE Key from Xiaomi Cloud. You can get it on many ways but I recommend 'Xiaomi Cloud Tokens Extractor'
Go to <a target="_blank" rel="noopener noreferrer" href="https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor">https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor</a> and use your preferred way.
Find Xiaomi Body Composition Scale S400 on the list of your devices and copy BLE KEY and MAC and save it for later.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/token_extractor.png"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/token_extractor.png" alt="Xiaomi Cloud Tokens Extractor" style="width: 836px; margin: auto; display: block;"></a>
3. Now you need to completely kill the app (so that it doesn't run in the background either). Or remove the scale from the list of devices - if you use other devices with Xiaomi Home. The scale will only send the needed data when it is not able to connect to the Xiaomi Home app! Every time when you add Scale as new device to Xiaomi Home new BLE key will be generated.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/xiaomi_home.png"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/xiaomi_home.png" alt="Xiaomi Homer" style="width: 400px; margin: auto;
display: block;"></a>
4. Now got MiScale Exporter settings, select S400 scale and paste MAC address and BLE Key.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/s400_settings.png"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/s400_settings.png" alt="S400 settings" style="width: 400px; margin: auto;
display: block;"></a>
5. The scale only sends data in a short time window at the end of weighing, so it's important to start the measurement before stepping on the scale. The Bluetooth icon should blink. (Watch the video below)
[](https://www.youtube.com/shorts/HtOZZwnkZHw)
6. These types of scales do not measure body composition. They measure weight and impedance and estimate the result based on those measurements. The scale sends 3 values: Weight, impedance and Heart rate. To receive body composition data, impedance is processed by an algorithm known to be similar to that used by the Mi Body Composition Scale 2 (different from that used by the S400). Because of this, the result may differ from that of the Xiaomi Home app. For this calculation proper age, height and sex is needed.
7. Bear in mind that it is an experimental solution and errors may occur. If you encounter them, please contact me.
## Garmin Connect Upload
1. After successfully retrieving data from the scale, you will be redirected to the Garmin data form.
2. Here you can see the result of your measurement and send it to the Garmin Connect cloud.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/bodycomposition.jpg"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/bodycomposition.jpg" alt="calculated body composition" style="width: 400px; margin: auto;
display: block;"></a>
3. If you have set up your email and password in the settings, you do not need to enter anything else here.
4. This app support 2FA/MFA codes. If you use MFA security, you will receive a message asking you to enter a code when you first try to send a message. It should be sent to your email address or as a text message to your phone (depending on your region). Close the message and enter the code in the new MFA field that appears at the bottom of the screen.
5. You don't have to enter the code every time you try to send a message. The returned token will be saved in the app and will be valid for several months.
<a target="_blank" rel="noopener noreferrer" href="https://github.com/lswiderski/mi-scale-exporter/blob/main/resources/img/screenshots/garmin.png"><img src="https://github.com/lswiderski/mi-scale-exporter/raw/main/resources/img/screenshots/garmin.png" alt="Garmin results" style="width: 722px; margin: auto;
display: block;"></a>
================================================
FILE: src/MiScaleExporter.MAUI/App.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<Application
x:Class="MiScaleExporter.MAUI.App"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MiScaleExporter.MAUI"
xmlns:converters="clr-namespace:MiScaleExporter.MAUI.Converters">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
<converters:InvertedBoolConverter x:Key="InvertedBoolConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
================================================
FILE: src/MiScaleExporter.MAUI/App.xaml.cs
================================================
using Autofac;
using Autofac.Extras.CommonServiceLocator;
using CommonServiceLocator;
using MiScaleExporter.Models;
using MiScaleExporter.Services;
using MiScaleExporter.MAUI.ViewModels;
using IContainer = Autofac.IContainer;
using MiScaleExporter.Droid;
using System.Globalization;
using CommunityToolkit.Maui.Storage;
namespace MiScaleExporter.MAUI
{
public partial class App : Application
{
public static IContainer Container;
public static BodyComposition BodyComposition;
public App()
{
CultureInfo.DefaultThreadCurrentCulture = Thread.CurrentThread.CurrentCulture;
InitializeComponent();
}
protected override Window CreateWindow(IActivationState activationState)
{
// Workaround for: 'Either set MainPage or override CreateWindow.'??
if (this.MainPage == null)
{
AutofacInit();
this.MainPage = new AppShell();
}
return base.CreateWindow(activationState);
}
protected override void OnStart()
{
base.OnStart();
AutofacInit();
MainPage = new AppShell();
}
protected void AutofacInit()
{
// Initialize Autofac builder
var builder = new ContainerBuilder();
// Register services
builder.RegisterType<Scale>().As<IScale>().InstancePerLifetimeScope();
builder.RegisterType<DataInterpreter>().As<IDataInterpreter>().InstancePerLifetimeScope();
builder.RegisterType<GarminService>().As<IGarminService>().InstancePerLifetimeScope();
builder.RegisterType<ScaleViewModel>().As<IScaleViewModel>().InstancePerLifetimeScope();
builder.RegisterType<FormViewModel>().As<IFormViewModel>().InstancePerLifetimeScope();
builder.RegisterType<LogService>().As<ILogService>().SingleInstance();
builder.RegisterType<SettingsViewModel>().As<ISettingsViewModel>().InstancePerLifetimeScope();
builder.RegisterType<AboutViewModel>().AsSelf();
builder.RegisterInstance<IFileSaver>(FileSaver.Default).SingleInstance();
App.Container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(Container));
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/AppShell.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="MiScaleExporter.MAUI.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:MiScaleExporter.Controls"
xmlns:local="clr-namespace:MiScaleExporter.MAUI.Views"
xmlns:localization="clr-namespace:MiScaleExporter.MAUI.Resources.Localization"
FlyoutBackgroundImageAspect="AspectFill"
FlyoutHeaderBehavior="CollapseOnScroll">
<Shell.Resources>
<ResourceDictionary>
<Style x:Key="BaseStyle" TargetType="Element">
<Setter Property="Shell.BackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.ForegroundColor" Value="White" />
<Setter Property="Shell.TitleColor" Value="White" />
<Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" />
<Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.TabBarForegroundColor" Value="White" />
<Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF" />
<Setter Property="Shell.TabBarTitleColor" Value="White" />
</Style>
<Style BasedOn="{StaticResource BaseStyle}" TargetType="TabBar" />
<Style BasedOn="{StaticResource BaseStyle}" TargetType="FlyoutItem" />
<!--
Default Styles for all Flyout Items
https://docs.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/flyout#flyoutitem-and-menuitem-style-classes
-->
<Style Class="FlyoutItemLabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="White" />
</Style>
<Style
ApplyToDerivedTypes="True"
Class="FlyoutItemLayoutStyle"
TargetType="Layout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{x:OnPlatform UWP=Transparent, iOS=White}" />
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{StaticResource Primary}" />
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<!--
Custom Style you can apply to any Flyout Item
-->
<Style
ApplyToDerivedTypes="True"
Class="MenuItemLayoutStyle"
TargetType="Layout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
</Shell.Resources>
<Shell.FlyoutHeader>
<controls:FlyoutHeader />
</Shell.FlyoutHeader>
<Shell.FlyoutFooter>
<controls:FlyoutFooter />
</Shell.FlyoutFooter>
<FlyoutItem Title="{x:Static localization:AppSnippets.Start}">
<FlyoutItem.Icon>
<FontImageSource
FontFamily="FontAwesome6Solid"
Glyph=""
Size="16"
Color="{AppThemeBinding Light={StaticResource Black},
Dark={StaticResource White}}" />
</FlyoutItem.Icon>
<ShellContent ContentTemplate="{DataTemplate local:AboutPage}" Route="AboutPage" />
</FlyoutItem>
<FlyoutItem Title="{x:Static localization:AppSnippets.MiScale}">
<FlyoutItem.Icon>
<FontImageSource
FontFamily="FontAwesome6Solid"
Glyph=""
Size="16"
Color="{AppThemeBinding Light={StaticResource Black},
Dark={StaticResource White}}" />
</FlyoutItem.Icon>
<ShellContent ContentTemplate="{DataTemplate local:ScalePage}" Route="ScalePage" />
</FlyoutItem>
<FlyoutItem Title="{x:Static localization:AppSnippets.GarminForm}">
<FlyoutItem.Icon>
<FontImageSource
FontFamily="FontAwesome6Solid"
Glyph=""
Size="16"
Color="{AppThemeBinding Light={StaticResource Black},
Dark={StaticResource White}}" />
</FlyoutItem.Icon>
<ShellContent ContentTemplate="{DataTemplate local:FormPage}" Route="FormPage" />
</FlyoutItem>
<FlyoutItem Title="{x:Static localization:AppSnippets.Settings}">
<FlyoutItem.Icon>
<FontImageSource
FontFamily="FontAwesome6Solid"
Glyph=""
Size="16"
Color="{AppThemeBinding Light={StaticResource Black},
Dark={StaticResource White}}" />
</FlyoutItem.Icon>
<ShellContent ContentTemplate="{DataTemplate local:SettingPage}" Route="Settings" />
</FlyoutItem>
<FlyoutItem Title="{x:Static localization:AppSnippets.Help}">
<FlyoutItem.Icon>
<FontImageSource
FontFamily="FontAwesome6Solid"
Glyph=""
Size="16"
Color="{AppThemeBinding Light={StaticResource Black},
Dark={StaticResource White}}" />
</FlyoutItem.Icon>
<ShellContent ContentTemplate="{DataTemplate local:HelpPage}" Route="HelpPage" />
</FlyoutItem>
</Shell>
================================================
FILE: src/MiScaleExporter.MAUI/AppShell.xaml.cs
================================================
namespace MiScaleExporter.MAUI
{
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
private async void OnMenuItemClicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("..");
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Behaviors/NumericDoubleValidationBehavior.cs
================================================
using MiScaleExporter.MAUI.Utils;
namespace MiScaleExporter.MAUI.Behaviors;
public class NumericDoubleValidationBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
bool isValid = DoubleValueParser.IsValid(args.NewTextValue);
var defaultColor = Application.Current.RequestedTheme == AppTheme.Dark ? Color.FromRgb(255, 255, 255) : Color.FromRgb(0, 0, 0);
((Entry)sender).TextColor = isValid ? defaultColor : Color.FromRgb(255, 0, 0);
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Behaviors/NumericIntValidationBehavior.cs
================================================
namespace MiScaleExporter.MAUI.Behaviors;
public class NumericIntValidationBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
bool isValid = int.TryParse(args.NewTextValue, out _);
var defaultColor = Application.Current.RequestedTheme == AppTheme.Dark ? Color.FromRgb(255, 255, 255) : Color.FromRgb(0, 0, 0);
((Entry)sender).TextColor = isValid ? defaultColor : Color.FromRgb(255, 0, 0);
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Controls/FlyoutFooter.xaml
================================================
<?xml version="1.0" encoding="utf-8" ?>
<ContentView
x:Class="MiScaleExporter.Controls.FlyoutFooter"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:localization="clr-namespace:MiScaleExporter.MAUI.Resources.Localization">
<VerticalStackLayout>
<Label
Margin="10"
FontSize="Small"
HorizontalOptions="Center"
Text="{x:Static localization:AppSnippets.CreatedBy}" />
</VerticalStackLayout>
</ContentView>
================================================
FILE: src/MiScaleExporter.MAUI/Controls/FlyoutFooter.xaml.cs
================================================
namespace MiScaleExporter.Controls;
public partial class FlyoutFooter : ContentView
{
public FlyoutFooter()
{
InitializeComponent();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Controls/FlyoutHeader.xaml
================================================
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MiScaleExporter.Controls.FlyoutHeader">
<VerticalStackLayout>
<Label
Text="Mi Scale Exporter"
VerticalOptions="Center"
HorizontalOptions="Center"
Margin="40"/>
</VerticalStackLayout>
</ContentView>
================================================
FILE: src/MiScaleExporter.MAUI/Controls/FlyoutHeader.xaml.cs
================================================
namespace MiScaleExporter.Controls;
public partial class FlyoutHeader : ContentView
{
public FlyoutHeader()
{
InitializeComponent();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Converters/InvertedBoolConverter.cs
================================================
using System.Globalization;
namespace MiScaleExporter.MAUI.Converters;
public class InvertedBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return !boolValue;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return !boolValue;
}
return value;
}
}
================================================
FILE: src/MiScaleExporter.MAUI/MauiProgram.cs
================================================
using CommunityToolkit.Maui;
using Plugin.AdMob;
using Plugin.AdMob.Configuration;
namespace MiScaleExporter.MAUI
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>().ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
fonts.AddFont("FontAwesome6Regular.otf", "FontAwesome6Regular");
fonts.AddFont("FontAwesome6Solid.otf", "FontAwesome6Solid");
}).UseMauiCommunityToolkit()
.UseAdMob();
#if DEBUG
//AdConfig.UseTestAdUnitIds = true;
#endif
AdConfig.DefaultBannerAdUnitId = "ca-app-pub-1938975042085430/4160336701";
return builder.Build();
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/MiScaleExporter.MAUI.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net9.0-android</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>MiScaleExporter.MAUI</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<UseNativeHttpHandler>false</UseNativeHttpHandler>
<!-- Display name -->
<ApplicationTitle>MiScaleExporter.MAUI</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.lukaszswiderski.miscaleexporter.maui</ApplicationId>
<ApplicationIdGuid>f67014c4-0bdb-47bd-b669-da42bf0d67c4</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">23.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android|AnyCPU'">
<ApplicationDisplayVersion>2.4.0</ApplicationDisplayVersion>
<ApplicationVersion>37</ApplicationVersion>
<AndroidUseAapt2>True</AndroidUseAapt2>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<UseNativeHttpHandler Condition="'$(UseNativeHttpHandler)' == ''">true</UseNativeHttpHandler>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-android|AnyCPU'">
<ApplicationDisplayVersion>2.4.0</ApplicationDisplayVersion>
<ApplicationVersion>37</ApplicationVersion>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<AndroidUseAapt2>True</AndroidUseAapt2>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<UseNativeHttpHandler Condition="'$(UseNativeHttpHandler)' == ''">true</UseNativeHttpHandler>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net9.0-android|AnyCPU'">
<AndroidPackageFormat>apk</AndroidPackageFormat>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\launcher_foreground.png" Color="#FFFFFF" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splashscale.png" BaseSize="128,128" Resize="false" Color="#FFFFFF" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.81" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.81" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="8.3.0" />
<PackageReference Include="Autofac.Extras.CommonServiceLocator" Version="6.1.0" />
<PackageReference Include="CommunityToolkit.Maui" Version="12.1.0" />
<PackageReference Include="MiScaleBodyComposition" Version="1.0.12" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.3.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.9" />
<PackageReference Include="Plugin.AdMob" Version="2.3.2-beta.7" />
<PackageReference Include="Plugin.BLE" Version="3.2.0-beta.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="YetAnotherGarminConnectClient" Version="0.0.14" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization\AppSnippets.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>AppSnippets.resx</DependentUpon>
</Compile>
<Compile Update="Views\AboutPage.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Views\FormPage.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Views\ScalePage.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Views\SettingsPage.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization\AppSnippets.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppSnippets.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<MauiXaml Update="Controls\FlyoutFooter.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Controls\FlyoutHeader.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\AboutPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\FormPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\HelpPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\ScalePage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\SettingsPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
</ItemGroup>
</Project>
================================================
FILE: src/MiScaleExporter.MAUI/Models/BodyComposition.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
namespace MiScaleExporter.Models
{
public class BodyComposition
{
public double BMI { get; set; }
public double Weight { get; set; }
public double IdealWeight { get; set; }
public double MetabolicAge { get; set; }
public double ProteinPercentage { get; set; }
public double BMR { get; set; }
public double Fat { get; set; }
public double MuscleMass { get; set; }
public double BoneMass { get; set; }
public double VisceralFat { get; set; }
public int BodyType { get; set; }
public double WaterPercentage { get; set; }
public bool IsValid { get; set; }
public bool HasImpedance { get; set; }
public bool IsStabilized { get; set; }
public DateTime Date { get; set; }
public byte[] ReceivedRawData { get; set; }
public string MFACode { get; set; }
public string ExternalApiClientId { get; set; }
public List<byte[]> RawDataLog { get; set; }
public BodyComposition()
{
RawDataLog = new List<byte[]>();
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/GarminApiResponse.cs
================================================
namespace MiScaleExporter.Models;
public class GarminApiResponse
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public bool MFARequested { get; set; }
public string ExternalApiClientId { get; set; }
public string AccessToken { get; set; }
public string TokenSecret { get; set; }
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/GarminBodyCompositionRequest.cs
================================================
namespace MiScaleExporter.Models;
public record GarminBodyCompositionRequest
{
public long TimeStamp { get; set; }
public double Weight { get; set; }
public double PercentFat { get; set; }
public double PercentHydration { get; set; }
public double BoneMass { get; set; }
public double MuscleMass { get; set; }
public double VisceralFatRating{ get; set; }
public int PhysiqueRating { get; set; }
public double MetabolicAge { get; set; }
public double BodyMassIndex { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ClientID { get; set; }
public string MFACode { get; set; }
public string AccessToken { get; set; }
public string TokenSecret { get; set; }
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/GarminExternalApiResponse.cs
================================================
using YetAnotherGarminConnectClient.Dto;
namespace MiScaleExporter.Models
{
public record GarminExternalApiResponse
{
public string ClientId { get; set; }
public GarminUploadResult UploadResult { get; set; }
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/GarminFitFileCreationResult.cs
================================================
namespace MiScaleExporter.Models;
public class GarminFitFileCreationResult
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public byte[] file { get; set; }
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/GarminUploadResult.cs
================================================
using YetAnotherGarminConnectClient.Dto;
namespace MiScaleExporter.Models
{
public record GarminUploadResult
{
public bool IsSuccess { get; set; }
public long UploadId { get; set; }
public IList<string> Logs { get; set; }
public IList<string> ErrorLogs { get; set; }
public AuthStatus AuthStatus { get; set; }
public bool MFACodeRequested { get; set; }
public string? AccessToken { get; set; }
public string? TokenSecret { get; set; }
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/PreferencesKeys.cs
================================================
namespace MiScaleExporter.Models;
public static class PreferencesKeys
{
public static string UserAge = "UserAge";
public static string UserBirthDate = "UserBirthDate";
public static string UseBirthDateMode = "UseBirthDateMode";
public static string UserHeight = "UserHeight";
public static string UserSex = "UserSex";
public static string MiScaleBluetoothAddress = "MiScaleBluetoothAddress";
public static string GarminUserEmail = "GarminUserEmail";
public static string GarminUserSavePassword = "GarminUserSavePassword";
public static string GarminUserPassword = "GarminUserPassword";
public static string GarminUserAccessToken = "GarminUserAccessToken";
public static string GarminUserTokenSecret = "GarminUserTokenSecret";
public static string ApiServerAddressOverride = "ApiServerAddressOverride";
public static string ScaleType = "ScaleType";
public static string OneClickScanAndUpload = "OneClickScanAndUpload";
public static string UseExternalAPI = "UseExternalAPI";
public static string ShowDebugInfo = "ShowDebugInfo";
public static string HideAds = "HideAds";
public static string MuscleMassAsPercentage = "MuscleMassAsPercentage";
public static string S400Bindkey = "S400Bindkey";
public static string DisplayWeightInLbs = "DisplayWeightInLbs";
public static string UseChinaServer = "UseChinaServer";
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/ScaleMeasurement.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MiScaleExporter.Models
{
public class ScaleMeasurement : INotifyPropertyChanged
{
private ScaleMeasurement() { }
public static ScaleMeasurement Instance { get; } = new ScaleMeasurement();
private string _weight;
public string Weight
{
get => _weight;
set
{
if (_weight != value)
{
_weight = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(Weight)));
}
}
}
private string _foundScale;
public string FoundScale
{
get => _foundScale;
set
{
if (_foundScale != value)
{
_foundScale = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(FoundScale)));
}
}
}
private string _debugData;
public string DebugData
{
get => _debugData;
set
{
if (_debugData != value)
{
_debugData = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(DebugData)));
}
}
}
private string _rawData;
public string RawData
{
get => _rawData;
set
{
if (_rawData != value)
{
_rawData = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(RawData)));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/ScaleType.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
namespace MiScaleExporter.Models
{
public enum ScaleType : byte
{
MiBodyCompositionScale = 0,
MiSmartScale = 1,
S400 = 2,
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/SettingKeys.cs
================================================
namespace MiScaleExporter.Models;
public static class SettingKeys
{
public static string ApiServerAddress = "https://frog01-20364.wykr.es";
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/Sex.cs
================================================
namespace MiScaleExporter.Models
{
public enum Sex : byte
{
Male = 0,
Female = 1,
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Models/User.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
namespace MiScaleExporter.Models
{
public class User
{
public int Height { get; set; }
public int Age { get; set; }
public Sex Sex { get; set; }
public ScaleType ScaleType { get; set; }
public string BindKey { get; set; }
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Permission/BluetoothConnectPermission.cs
================================================
using MiScaleExporter.Permission;
using System;
using System.Collections.Generic;
using System.Text;
namespace MiScaleExporter.Droid
{
public class BluetoothConnectPermission : Permissions.BasePlatformPermission, IBluetoothConnectPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)>
{
(Android.Manifest.Permission.BluetoothConnect, true),
(Android.Manifest.Permission.BluetoothScan, true),
(Android.Manifest.Permission.BluetoothAdvertise, true),
}.ToArray();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Permission/IBluetoothConnectPermission.cs
================================================
namespace MiScaleExporter.Permission
{
public interface IBluetoothConnectPermission
{
Task<PermissionStatus> CheckStatusAsync();
Task<PermissionStatus> RequestAsync();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Android/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="37" android:versionName="2.4.0" package="com.lukaszswiderski.MiScaleExporter" android:installLocation="auto">
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
<application android:label="MiScale Exporter" android:usesCleartextTraffic="true" android:theme="@style/MainTheme" android:icon="@mipmap/launcher_foreground" android:allowBackup="false" android:requestLegacyExternalStorage="true">
<activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:theme="@android:style/Theme.Translucent" />
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-1938975042085430~7383010816" />
</application>
</manifest>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Android/MainActivity.cs
================================================
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using MiScaleExporter.Droid;
using MiScaleExporter.Permission;
namespace MiScaleExporter.MAUI
{
[Activity(Label = "MiScale Exporter", Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Platform.Init(this, savedInstanceState);
DependencyService.Register<IBluetoothConnectPermission, BluetoothConnectPermission>();
// LoadApplication(app);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Android/MainApplication.cs
================================================
using Android.App;
using Android.Runtime;
namespace MiScaleExporter.MAUI
{
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Android/Resources/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="launcher_background">#FFFFFF</color>
<color name="colorPrimary">#007CC3</color>
<color name="colorPrimaryDark">#004b76</color>
<color name="colorAccent">#007CC3</color>
</resources>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Android/Resources/values/styles.xml
================================================
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MainTheme" parent="MainTheme.Base">
</style>
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">#f2f2f2</item>
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:textColorPrimary">#000000</item>
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
<!-- As of Xamarin.Forms 4.6 the theme has moved into the Forms binary -->
<!-- If you want to override anything you can do that here. -->
<!-- Underneath are a couple of entries to get you started. -->
<!-- Set theme colors from https://aka.ms/material-colors -->
<!-- colorPrimary is used for the default action bar background -->
<!--<item name="colorPrimary">#2196F3</item>-->
<!-- colorPrimaryDark is used for the status bar -->
<!--<item name="colorPrimaryDark">#1976D2</item>-->
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#2e2e2e</item>
</style>
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#FF4081</item>
</style>
</resources>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/MacCatalyst/AppDelegate.cs
================================================
using Foundation;
namespace MiScaleExporter.MAUI
{
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/MacCatalyst/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/MacCatalyst/Program.cs
================================================
using ObjCRuntime;
using UIKit;
namespace MiScaleExporter.MAUI
{
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Tizen/Main.cs
================================================
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using System;
namespace MiScaleExporter.MAUI
{
internal class Program : MauiApplication
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
static void Main(string[] args)
{
var app = new Program();
app.Run(args);
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Tizen/tizen-manifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="7" xmlns="http://tizen.org/ns/packages">
<profile name="common" />
<ui-application appid="maui-application-id-placeholder" exec="MiScaleExporter.MAUI.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
<label>maui-application-title-placeholder</label>
<icon>maui-appicon-placeholder</icon>
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
</ui-application>
<shortcut-list />
<privileges>
<privilege>http://tizen.org/privilege/internet</privilege>
</privileges>
<dependencies />
<provides-appdefined-privileges />
</manifest>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Windows/App.xaml
================================================
<maui:MauiWinUIApplication
x:Class="MiScaleExporter.MAUI.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:MiScaleExporter.MAUI.WinUI">
</maui:MauiWinUIApplication>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Windows/App.xaml.cs
================================================
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace MiScaleExporter.MAUI.WinUI
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : MauiWinUIApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Windows/Package.appxmanifest
================================================
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
<Properties>
<DisplayName>$placeholder$</DisplayName>
<PublisherDisplayName>User Name</PublisherDisplayName>
<Logo>$placeholder$.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="$placeholder$"
Description="$placeholder$"
Square150x150Logo="$placeholder$.png"
Square44x44Logo="$placeholder$.png"
BackgroundColor="transparent">
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
<uap:SplashScreen Image="$placeholder$.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/Windows/app.manifest
================================================
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MiScaleExporter.MAUI.WinUI.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/iOS/AppDelegate.cs
================================================
using Foundation;
namespace MiScaleExporter.MAUI
{
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/iOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
================================================
FILE: src/MiScaleExporter.MAUI/Platforms/iOS/Program.cs
================================================
using ObjCRuntime;
using UIKit;
namespace MiScaleExporter.MAUI
{
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Properties/launchSettings.json
================================================
{
"profiles": {
"Windows Machine": {
"commandName": "MsixPackage",
"nativeDebugging": false
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.Designer.cs
================================================
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MiScaleExporter.MAUI.Resources.Localization {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class AppSnippets {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AppSnippets() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MiScaleExporter.MAUI.Resources.Localization.AppSnippets", typeof(AppSnippets).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to This application is an open source community project and I have no affiliation with Garmin..
/// </summary>
internal static string AboutGarmin {
get {
return ResourceManager.GetString("AboutGarmin", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Set the bluetooth address of the scale, and your data in the settings. Stand on your scale. Measure yourself. Mi Body Composition Scale is active up to 15 min after the measurement..
/// </summary>
internal static string AboutMeasureInstruction {
get {
return ResourceManager.GetString("AboutMeasureInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The application now supports MFA/2FA security features. If you save credentials in settings, authorization tokens will be remembered and you won't be asked every time for MFA code..
/// </summary>
internal static string AboutMFAAndStoringData {
get {
return ResourceManager.GetString("AboutMFAAndStoringData", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Then you can review your data and upload it to Garmin Cloud. If you do not have Mi scale and just want to manually insert the data, you can so..
/// </summary>
internal static string AboutUpload {
get {
return ResourceManager.GetString("AboutUpload", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Age.
/// </summary>
internal static string Age {
get {
return ResourceManager.GetString("Age", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Alternate External API Address.
/// </summary>
internal static string AlternateExternalAPIAddress {
get {
return ResourceManager.GetString("AlternateExternalAPIAddress", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to App Settings.
/// </summary>
internal static string AppSettings {
get {
return ResourceManager.GetString("AppSettings", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Basal Metabolism (kCal):.
/// </summary>
internal static string BasalMetabolosimKCal {
get {
return ResourceManager.GetString("BasalMetabolosimKCal", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Bluetooth Address.
/// </summary>
internal static string BluetoothAddress {
get {
return ResourceManager.GetString("BluetoothAddress", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to BMI.
/// </summary>
internal static string BMI {
get {
return ResourceManager.GetString("BMI", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Body age (years).
/// </summary>
internal static string BodyAgeYears {
get {
return ResourceManager.GetString("BodyAgeYears", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Body Fat (%).
/// </summary>
internal static string BodyFatPercent {
get {
return ResourceManager.GetString("BodyFatPercent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Body Type.
/// </summary>
internal static string BodyType {
get {
return ResourceManager.GetString("BodyType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Bone mass (Lbs).
/// </summary>
internal static string BoneMassLbs {
get {
return ResourceManager.GetString("BoneMassLbs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Bone mass (Kg).
/// </summary>
internal static string BoneMassPercent {
get {
return ResourceManager.GetString("BoneMassPercent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Buy me a coffee.
/// </summary>
internal static string BuyMeACoffee {
get {
return ResourceManager.GetString("BuyMeACoffee", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cancel MFA Request.
/// </summary>
internal static string CancelMFARequest {
get {
return ResourceManager.GetString("CancelMFARequest", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cancel Search.
/// </summary>
internal static string CancelSearch {
get {
return ResourceManager.GetString("CancelSearch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Created by Lukasz Swiderski 2023.
/// </summary>
internal static string CreatedBy {
get {
return ResourceManager.GetString("CreatedBy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Data could not be obtained. try again.
/// </summary>
internal static string DataCouldNotBeObtained {
get {
return ResourceManager.GetString("DataCouldNotBeObtained", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Do you like this app and would you like to support it?.
/// </summary>
internal static string DoYouLikeAndWouldYouLikeToSupport {
get {
return ResourceManager.GetString("DoYouLikeAndWouldYouLikeToSupport", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Email.
/// </summary>
internal static string Email {
get {
return ResourceManager.GetString("Email", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Female.
/// </summary>
internal static string Female {
get {
return ResourceManager.GetString("Female", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Garmin Body Composition Form.
/// </summary>
internal static string GarminBodyCompositionForm {
get {
return ResourceManager.GetString("GarminBodyCompositionForm", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Garmin Form.
/// </summary>
internal static string GarminForm {
get {
return ResourceManager.GetString("GarminForm", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Garmin Settings.
/// </summary>
internal static string GarminSettings {
get {
return ResourceManager.GetString("GarminSettings", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Generate only .fit file.
/// </summary>
internal static string GenerateOnlyFitFile {
get {
return ResourceManager.GetString("GenerateOnlyFitFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Go to scan.
/// </summary>
internal static string GoToScan {
get {
return ResourceManager.GetString("GoToScan", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Height.
/// </summary>
internal static string Height {
get {
return ResourceManager.GetString("Height", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Help.
/// </summary>
internal static string Help {
get {
return ResourceManager.GetString("Help", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 8. Coffee.
/// </summary>
internal static string HelpCoffee {
get {
return ResourceManager.GetString("HelpCoffee", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep in mind that this is my hobby project. It was created for my inner needs and I believe it may be useful to others as well. I do not receive any compensation for creating and maintaining this project. If you want to support the development or thank me, you can buy me a coffee..
/// </summary>
internal static string HelpCoffeeDescription {
get {
return ResourceManager.GetString("HelpCoffeeDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 1. How to connect to the scale.
/// </summary>
internal static string HelpConnect {
get {
return ResourceManager.GetString("HelpConnect", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Set the Bluetooth address of the scale in settings. Set the correct age/height/gender values. Measure yourself. The scale is active for up to 15 minutes after measurement..
/// </summary>
internal static string HelpConnectDescription {
get {
return ResourceManager.GetString("HelpConnectDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Bluetooth address can be found in Zepp Life > Profile > My devices > Mi Body Composition Scale > Bluetooth address (hold to copy).
/// </summary>
internal static string HelpConnectDescription2 {
get {
return ResourceManager.GetString("HelpConnectDescription2", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 5. External Api.
/// </summary>
internal static string HelpExternalApi {
get {
return ResourceManager.GetString("HelpExternalApi", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to External API is used as a proxy for older Android phones (9 or lower). The default address is https://frog01-20364.wykr.es/. You can host your own version of the API and this app will send the data to your system instead of Garmin. Check out the project repository for more information..
/// </summary>
internal static string HelpExternalApiDescription {
get {
return ResourceManager.GetString("HelpExternalApiDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 7. Feedback & Contact.
/// </summary>
internal static string HelpFeedback {
get {
return ResourceManager.GetString("HelpFeedback", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to If you found a bug, need a feature or have an idea, share it with me at the project repository..
/// </summary>
internal static string HelpFeedbackDescription {
get {
return ResourceManager.GetString("HelpFeedbackDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 6. Garmin and Xiaomi.
/// </summary>
internal static string HelpGarminAndXiaomi {
get {
return ResourceManager.GetString("HelpGarminAndXiaomi", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This application is an open source community project and I have no affiliation with Garmin or Xiaomi. You use it at your own risk. You can always check out the source code on Github..
/// </summary>
internal static string HelpGarminAndXiaomiDescription {
get {
return ResourceManager.GetString("HelpGarminAndXiaomiDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 2. How It works.
/// </summary>
internal static string HelpHowItWorks {
get {
return ResourceManager.GetString("HelpHowItWorks", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This App pass your data, email and password directly to Garmin Cloud or via external API server. The API does not store or log anything, it's just a middleware between this App and Garmin services..
/// </summary>
internal static string HelpHowItWorksDescription {
get {
return ResourceManager.GetString("HelpHowItWorksDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3. Strange results? (Like 10kg only).
/// </summary>
internal static string HelpStrangeResults {
get {
return ResourceManager.GetString("HelpStrangeResults", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to If you have the Mi Body Composition Scale 2. Disable the 'Weight small object' option in Zepp Life.
/// </summary>
internal static string HelpStrangeResultsDescription {
get {
return ResourceManager.GetString("HelpStrangeResultsDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 4. Results different from Zepp Life.
/// </summary>
internal static string HelpZeppLifeDriference {
get {
return ResourceManager.GetString("HelpZeppLifeDriference", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Please check the age/height/gender parameters - should be identical in both apps. But even then, the values may be slightly different because we do not use the exact algorithm used by Xiaomi, but an alternative open source algorithm..
/// </summary>
internal static string HelpZeppLifeDriferenceDescription {
get {
return ResourceManager.GetString("HelpZeppLifeDriferenceDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Ideal Weight (Kg):.
/// </summary>
internal static string IdealWeightKg {
get {
return ResourceManager.GetString("IdealWeightKg", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Ideal Weight (Lbs):.
/// </summary>
internal static string IdealWeightLbs {
get {
return ResourceManager.GetString("IdealWeightLbs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Male.
/// </summary>
internal static string Male {
get {
return ResourceManager.GetString("Male", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to MFA Code.
/// </summary>
internal static string MFACode {
get {
return ResourceManager.GetString("MFACode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Mi Body Composition Scale 1 / 2.
/// </summary>
internal static string MiBodyCompositionScale {
get {
return ResourceManager.GetString("MiBodyCompositionScale", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Mi Scale.
/// </summary>
internal static string MiScale {
get {
return ResourceManager.GetString("MiScale", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Mi Scale Data.
/// </summary>
internal static string MiScaleData {
get {
return ResourceManager.GetString("MiScaleData", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Mi Scale Exporter.
/// </summary>
internal static string MiScaleExporter {
get {
return ResourceManager.GetString("MiScaleExporter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Mi Smart Scale.
/// </summary>
internal static string MiSmartScale {
get {
return ResourceManager.GetString("MiSmartScale", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Muscle mass as %.
/// </summary>
internal static string MuscleMassAsPercentage {
get {
return ResourceManager.GetString("MuscleMassAsPercentage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Muscle Mass (Kg).
/// </summary>
internal static string MuscleMassKg {
get {
return ResourceManager.GetString("MuscleMassKg", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Muscle Mass (Lbs).
/// </summary>
internal static string MuscleMassLbs {
get {
return ResourceManager.GetString("MuscleMassLbs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Muscle Mass (%).
/// </summary>
internal static string MuscleMassPer {
get {
return ResourceManager.GetString("MuscleMassPer", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not found.
/// </summary>
internal static string NotFound {
get {
return ResourceManager.GetString("NotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OK.
/// </summary>
internal static string OK {
get {
return ResourceManager.GetString("OK", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to One click - Scan & Upload.
/// </summary>
internal static string OneClickScanUpload {
get {
return ResourceManager.GetString("OneClickScanUpload", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open Help.
/// </summary>
internal static string OpenHelp {
get {
return ResourceManager.GetString("OpenHelp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Password.
/// </summary>
internal static string Password {
get {
return ResourceManager.GetString("Password", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Permission to use Bluetooth is required to scan..
/// </summary>
internal static string PermissionBluetoothRequired {
get {
return ResourceManager.GetString("PermissionBluetoothRequired", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Permission to use Location (Bluetooth) is required to scan..
/// </summary>
internal static string PermissionLocationRequired {
get {
return ResourceManager.GetString("PermissionLocationRequired", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Problem.
/// </summary>
internal static string Problem {
get {
return ResourceManager.GetString("Problem", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Protein (%):.
/// </summary>
internal static string ProteinPercent {
get {
return ResourceManager.GetString("ProteinPercent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reset to Default.
/// </summary>
internal static string ResetToDefault {
get {
return ResourceManager.GetString("ResetToDefault", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Response.
/// </summary>
internal static string Response {
get {
return ResourceManager.GetString("Response", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scale Model.
/// </summary>
internal static string ScaleModel {
get {
return ResourceManager.GetString("ScaleModel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scale Settings.
/// </summary>
internal static string ScaleSettings {
get {
return ResourceManager.GetString("ScaleSettings", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scanning....
/// </summary>
internal static string Scanning {
get {
return ResourceManager.GetString("Scanning", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Settings.
/// </summary>
internal static string Settings {
get {
return ResourceManager.GetString("Settings", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Hide Ads Banner.
/// </summary>
internal static string SettingsHideAds {
get {
return ResourceManager.GetString("SettingsHideAds", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sex.
/// </summary>
internal static string Sex {
get {
return ResourceManager.GetString("Sex", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show Debug Info during scan.
/// </summary>
internal static string ShowDebug {
get {
return ResourceManager.GetString("ShowDebug", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Start.
/// </summary>
internal static string Start {
get {
return ResourceManager.GetString("Start", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stop Measure.
/// </summary>
internal static string StopMeasure {
get {
return ResourceManager.GetString("StopMeasure", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Time of measurement.
/// </summary>
internal static string TimeOfMeasurement {
get {
return ResourceManager.GetString("TimeOfMeasurement", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Uploaded.
/// </summary>
internal static string Uploaded {
get {
return ResourceManager.GetString("Uploaded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Uploading....
/// </summary>
internal static string Uploading {
get {
return ResourceManager.GetString("Uploading", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Upload to Garmin Cloud.
/// </summary>
internal static string UploadToGarminCloud {
get {
return ResourceManager.GetString("UploadToGarminCloud", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use External API.
/// </summary>
internal static string UseExternalAPI {
get {
return ResourceManager.GetString("UseExternalAPI", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Values that will not be sent to the cloud:.
/// </summary>
internal static string ValuesThatWillNotBeSentToTheCloud {
get {
return ResourceManager.GetString("ValuesThatWillNotBeSentToTheCloud", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Visceral fat.
/// </summary>
internal static string VisceralFat {
get {
return ResourceManager.GetString("VisceralFat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Visit the project repository.
/// </summary>
internal static string VisitProjectRepository {
get {
return ResourceManager.GetString("VisitProjectRepository", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Water (%).
/// </summary>
internal static string WaterPercent {
get {
return ResourceManager.GetString("WaterPercent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Weight (Kg).
/// </summary>
internal static string WeightKg {
get {
return ResourceManager.GetString("WeightKg", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Weight (Lbs).
/// </summary>
internal static string WeightLbs {
get {
return ResourceManager.GetString("WeightLbs", resourceCulture);
}
}
}
}
================================================
FILE: src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.pl.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutGarmin" xml:space="preserve">
<value>Ta aplikacja jest projektem społeczności open source i nie ma żadnych powiązań z firmą Garmin.</value>
</data>
<data name="AboutMeasureInstruction" xml:space="preserve">
<value>Ustaw w ustawieniach adres bluetooth wagi, oraz swoje dane. Stań na swojej wadze. Zmierz się. Mi Body Composition Scale jest aktywna do 15 min po dokonaniu pomiaru.</value>
</data>
<data name="AboutMFAAndStoringData" xml:space="preserve">
<value>Aplikacja obsługuje teraz funkcje bezpieczeństwa MFA/2FA. Jeśli zapiszesz dane uwierzytelniające w ustawieniach, tokeny autoryzacyjne zostaną zapamiętane i nie będziesz za każdym razem proszony o podanie kodu MFA.</value>
</data>
<data name="AboutUpload" xml:space="preserve">
<value>Następnie możesz przejrzeć swoje dane i przesłać je do Garmin Cloud. Jeśli nie masz wagi Mi Scale i możesz po prostu ręcznie wprowadzić dane i przesłac je do Garmin Connect.</value>
</data>
<data name="Age" xml:space="preserve">
<value>Wiek</value>
</data>
<data name="AlternateExternalAPIAddress" xml:space="preserve">
<value>Alternatywny zewnętrzny adres API</value>
</data>
<data name="AppSettings" xml:space="preserve">
<value>Ustawienia aplikacji</value>
</data>
<data name="BasalMetabolosimKCal" xml:space="preserve">
<value>Metabolizm podstawowy (kCal):</value>
</data>
<data name="BluetoothAddress" xml:space="preserve">
<value>Adres Bluetooth</value>
</data>
<data name="BMI" xml:space="preserve">
<value>BMI</value>
</data>
<data name="BodyAgeYears" xml:space="preserve">
<value>Wiek ciała (w latach)</value>
</data>
<data name="BodyFatPercent" xml:space="preserve">
<value>Tłuszcz w organizmie (%)</value>
</data>
<data name="BodyType" xml:space="preserve">
<value>Typ Ciała</value>
</data>
<data name="BoneMassPercent" xml:space="preserve">
<value>Masa kostna (Kg)</value>
</data>
<data name="BoneMassLbs" xml:space="preserve">
<value>Masa kostna (Lbs)</value>
</data>
<data name="BuyMeACoffee" xml:space="preserve">
<value>Postaw mi kawę</value>
</data>
<data name="CancelMFARequest" xml:space="preserve">
<value>Anuluj MFA</value>
</data>
<data name="CancelSearch" xml:space="preserve">
<value>Anuluj wyszukiwanie</value>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Stworzone przez Łukasza Świderskiego 2023</value>
</data>
<data name="DataCouldNotBeObtained" xml:space="preserve">
<value>Nie udało się uzyskać danych. Spróbuj ponownie</value>
</data>
<data name="DoYouLikeAndWouldYouLikeToSupport" xml:space="preserve">
<value>Czy podoba Ci się ta aplikacja i chciałbyś ją wesprzeć?</value>
</data>
<data name="Email" xml:space="preserve">
<value>Email</value>
</data>
<data name="Female" xml:space="preserve">
<value>Kobieta</value>
</data>
<data name="GarminBodyCompositionForm" xml:space="preserve">
<value>Formularz składu ciała Garmin</value>
</data>
<data name="GarminForm" xml:space="preserve">
<value>Formularz Garmin</value>
</data>
<data name="GarminSettings" xml:space="preserve">
<value>Ustawienia Garmin</value>
</data>
<data name="GenerateOnlyFitFile" xml:space="preserve">
<value>Generuj tylko plik .fit</value>
</data>
<data name="GoToScan" xml:space="preserve">
<value>Przejdź do skanowania</value>
</data>
<data name="Height" xml:space="preserve">
<value>Wzrost</value>
</data>
<data name="Help" xml:space="preserve">
<value>Pomoc</value>
</data>
<data name="HelpCoffee" xml:space="preserve">
<value>8. Kawa</value>
</data>
<data name="HelpCoffeeDescription" xml:space="preserve">
<value>Należy pamiętać, że jest to mój projekt hobbystyczny. Został on stworzony dla moich wewnętrznych potrzeb i wierzę, że może być przydatny również dla innych. Nie otrzymuję żadnego wynagrodzenia za stworzenie i utrzymanie tego projektu. Jeśli chcesz wesprzeć rozwój lub podziękować mi, możesz postawić mi kawę.</value>
</data>
<data name="HelpConnect" xml:space="preserve">
<value>1. Jak podłączyć się do wagi</value>
</data>
<data name="HelpConnectDescription" xml:space="preserve">
<value>Ustawić adres Bluetooth wagi w ustawieniach. Ustaw prawidłowe wartości wieku/wzrostu/płci. Zmierz się. Waga jest aktywna i wysyła wyniki do 15 minut po pomiarze.</value>
</data>
<data name="HelpConnectDescription2" xml:space="preserve">
<value>Adres Bluetooth można znaleźć w Zepp Life > Profil > Moje urządzenia > Mi Body Composition Scale > Adres Bluetooth (przytrzymaj, aby skopiować)</value>
</data>
<data name="HelpExternalApi" xml:space="preserve">
<value>5. Zewnętrzne Api</value>
</data>
<data name="HelpExternalApiDescription" xml:space="preserve">
<value>Zewnętrzny interfejs API jest używany jako proxy dla starszych telefonów z systemem Android (9 lub niższy). Domyślny adres to https://frog01-20364.wykr.es/. Możesz hostować własną wersję API, a ta aplikacja wyśle dane do twojego systemu zamiast do Garmina. Sprawdź repozytorium projektu, aby uzyskać więcej informacji.</value>
</data>
<data name="HelpFeedback" xml:space="preserve">
<value>7. Informacje zwrotne i kontakt</value>
</data>
<data name="HelpFeedbackDescription" xml:space="preserve">
<value>Jeśli znalazłeś błąd, potrzebujesz jakiejś funkcji lub masz pomysł, podziel się nim ze mną w repozytorium projektu.</value>
</data>
<data name="HelpGarminAndXiaomi" xml:space="preserve">
<value>6. Garmin i Xiaomi</value>
</data>
<data name="HelpGarminAndXiaomiDescription" xml:space="preserve">
<value>Ta aplikacja jest otwarto-źródłowym projektem społeczności i nie ma żadnych powiązań z Garminem lub Xiaomi. Używasz jej na własne ryzyko. Zawsze możesz sprawdzić kod źródłowy na Githubie.</value>
</data>
<data name="HelpHowItWorks" xml:space="preserve">
<value>2. Jak to działa</value>
</data>
<data name="HelpHowItWorksDescription" xml:space="preserve">
<value>Ta aplikacja przekazuje Twoje dane, email i hasło bezpośrednio do Garmin Cloud lub poprzez zewnętrzny serwer API. API nie przechowuje ani nie rejestruje niczego, jest to tylko pośrednikiem pomiędzy aplikacją a usługami firmy Garmin.</value>
</data>
<data name="HelpStrangeResults" xml:space="preserve">
<value>3. Dziwne wyniki? (Np zwraca małe wartości jak 10kg)</value>
</data>
<data name="HelpStrangeResultsDescription" xml:space="preserve">
<value>Jeśli posiadasz Mi Body Composition Scale 2. Wyłącz opcję "Waż mały obiekt" w Zepp Life</value>
</data>
<data name="HelpZeppLifeDriference" xml:space="preserve">
<value>4. Wyniki różne od Zepp Life</value>
</data>
<data name="HelpZeppLifeDriferenceDescription" xml:space="preserve">
<value>Sprawdź parametry wieku/wzrostui/płci - powinny być identyczne w obu aplikacjach. Ale nawet wtedy wartości mogą być nieco inne, ponieważ nie używamy dokładnie takiego samego algorytmu jak Xiaomi, ale alternatywnego algorytmu open source.</value>
</data>
<data name="IdealWeightKg" xml:space="preserve">
<value>Idealna masa ciała (Kg):</value>
</data>
<data name="IdealWeightLbs" xml:space="preserve">
<value>Idealna masa ciała (Lbs):</value>
</data>
<data name="Male" xml:space="preserve">
<value>Mężczyzna</value>
</data>
<data name="MFACode" xml:space="preserve">
<value>Kod MFA</value>
</data>
<data name="MiBodyCompositionScale" xml:space="preserve">
<value>Mi Body Composition Scale 1 / 2</value>
</data>
<data name="MiScale" xml:space="preserve">
<value>Mi Scale</value>
</data>
<data name="MiScaleData" xml:space="preserve">
<value>Dane Mi Scale</value>
</data>
<data name="MiScaleExporter" xml:space="preserve">
<value>Mi Scale Exporter</value>
</data>
<data name="MiSmartScale" xml:space="preserve">
<value>Mi Smart Scale</value>
</data>
<data name="MuscleMassAsPercentage" xml:space="preserve">
<value>Masa mięśniowa jako %</value>
</data>
<data name="MuscleMassKg" xml:space="preserve">
<value>Masa mięśniowa (Kg)</value>
</data>
<data name="MuscleMassLbs" xml:space="preserve">
<value>Masa mięśniowa (Lbs)</value>
</data>
<data name="MuscleMassPer" xml:space="preserve">
<value>Masa mięśniowa (%)</value>
</data>
<data name="NotFound" xml:space="preserve">
<value>Nie znaleziono</value>
</data>
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="OneClickScanUpload" xml:space="preserve">
<value>Jedno kliknięcie - skanowanie i przesyłanie</value>
</data>
<data name="OpenHelp" xml:space="preserve">
<value>Otwórz pomoc</value>
</data>
<data name="Password" xml:space="preserve">
<value>Hasło</value>
</data>
<data name="PermissionBluetoothRequired" xml:space="preserve">
<value>Do skanowania wymagana jest zgoda na korzystanie z Bluetooth.</value>
</data>
<data name="PermissionLocationRequired" xml:space="preserve">
<value>Do skanowania wymagane jest pozwolenie na korzystanie z funkcji Lokalizacji (Bluetooth).</value>
</data>
<data name="BluetoothDisabled" xml:space="preserve">
<value>Bluetooth jest wyłączony. Włącz Bluetooth, aby skanować wagę Mi Scale.</value>
</data>
<data name="Problem" xml:space="preserve">
<value>Problem</value>
</data>
<data name="ProteinPercent" xml:space="preserve">
<value>Białko (%):</value>
</data>
<data name="ResetToDefault" xml:space="preserve">
<value>Przywrócenie ustawień domyślnych</value>
</data>
<data name="Response" xml:space="preserve">
<value>Odpowiedź</value>
</data>
<data name="ScaleModel" xml:space="preserve">
<value>Model Wagi</value>
</data>
<data name="ScaleSettings" xml:space="preserve">
<value>Ustawienia wagi</value>
</data>
<data name="Scanning" xml:space="preserve">
<value>Skanowanie...</value>
</data>
<data name="Settings" xml:space="preserve">
<value>Ustawienia</value>
</data>
<data name="SettingsHideAds" xml:space="preserve">
<value>Schowaj reklamy</value>
</data>
<data name="Sex" xml:space="preserve">
<value>Płeć</value>
</data>
<data name="ShowDebug" xml:space="preserve">
<value>Pokaż informacje debug podczas skanowania</value>
</data>
<data name="Start" xml:space="preserve">
<value>Start</value>
</data>
<data name="StopMeasure" xml:space="preserve">
<value>Zatrzymaj pomiar</value>
</data>
<data name="TimeOfMeasurement" xml:space="preserve">
<value>Czas pomiaru</value>
</data>
<data name="Uploaded" xml:space="preserve">
<value>Przesłano</value>
</data>
<data name="Uploading" xml:space="preserve">
<value>Wysyłanie...</value>
</data>
<data name="UploadToGarminCloud" xml:space="preserve">
<value>Prześlij do usługi Garmin Cloud</value>
</data>
<data name="UseExternalAPI" xml:space="preserve">
<value>Użyj zewnętrznego API</value>
</data>
<data name="ValuesThatWillNotBeSentToTheCloud" xml:space="preserve">
<value>Wartości, które nie będą wysyłane do chmury:</value>
</data>
<data name="VisceralFat" xml:space="preserve">
<value>Tłuszcz trzewny</value>
</data>
<data name="VisitProjectRepository" xml:space="preserve">
<value>Odwiedź repozytorium projektu</value>
</data>
<data name="WaterPercent" xml:space="preserve">
<value>Woda (%)</value>
</data>
<data name="WeightKg" xml:space="preserve">
<value>Waga (Kg)</value>
</data>
<data name="WeightLbs" xml:space="preserve">
<value>Waga (Lbs)</value>
</data>
</root>
================================================
FILE: src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutGarmin" xml:space="preserve">
<value>This application is an open source community project and I have no affiliation with Garmin.</value>
</data>
<data name="AboutMeasureInstruction" xml:space="preserve">
<value>Set the bluetooth address of the scale, and your data in the settings. Stand on your scale. Measure yourself. Mi Body Composition Scale is active up to 15 min after the measurement.</value>
</data>
<data name="AboutMFAAndStoringData" xml:space="preserve">
<value>The application now supports MFA/2FA security features. If you save credentials in settings, authorization tokens will be remembered and you won't be asked every time for MFA code.</value>
</data>
<data name="AboutUpload" xml:space="preserve">
<value>Then you can review your data and upload it to Garmin Cloud. If you do not have Mi scale and just want to manually insert the data, you can so.</value>
</data>
<data name="Age" xml:space="preserve">
<value>Age</value>
</data>
<data name="AlternateExternalAPIAddress" xml:space="preserve">
<value>Alternate External API Address</value>
</data>
<data name="AppSettings" xml:space="preserve">
<value>App Settings</value>
</data>
<data name="BasalMetabolosimKCal" xml:space="preserve">
<value>Basal Metabolism (kCal):</value>
</data>
<data name="BluetoothAddress" xml:space="preserve">
<value>Bluetooth Address</value>
</data>
<data name="BMI" xml:space="preserve">
<value>BMI</value>
</data>
<data name="BodyAgeYears" xml:space="preserve">
<value>Body age (years)</value>
</data>
<data name="BodyFatPercent" xml:space="preserve">
<value>Body Fat (%)</value>
</data>
<data name="BodyType" xml:space="preserve">
<value>Body Type</value>
</data>
<data name="BoneMassPercent" xml:space="preserve">
<value>Bone mass (Kg)</value>
</data>
<data name="BoneMassLbs" xml:space="preserve">
<value>Bone mass (Lbs)</value>
</data>
<data name="BuyMeACoffee" xml:space="preserve">
<value>Buy me a coffee</value>
</data>
<data name="CancelMFARequest" xml:space="preserve">
<value>Cancel MFA Request</value>
</data>
<data name="CancelSearch" xml:space="preserve">
<value>Cancel Search</value>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Created by Lukasz Swiderski 2023</value>
</data>
<data name="DataCouldNotBeObtained" xml:space="preserve">
<value>Data could not be obtained. try again</value>
</data>
<data name="DoYouLikeAndWouldYouLikeToSupport" xml:space="preserve">
<value>Do you like this app and would you like to support it?</value>
</data>
<data name="Email" xml:space="preserve">
<value>Email</value>
</data>
<data name="Female" xml:space="preserve">
<value>Female</value>
</data>
<data name="GarminBodyCompositionForm" xml:space="preserve">
<value>Garmin Body Composition Form</value>
</data>
<data name="GarminForm" xml:space="preserve">
<value>Garmin Form</value>
</data>
<data name="GarminSettings" xml:space="preserve">
<value>Garmin Settings</value>
</data>
<data name="GenerateOnlyFitFile" xml:space="preserve">
<value>Generate only .fit file</value>
</data>
<data name="GoToScan" xml:space="preserve">
<value>Go to scan</value>
</data>
<data name="Height" xml:space="preserve">
<value>Height</value>
</data>
<data name="Help" xml:space="preserve">
<value>Help</value>
</data>
<data name="HelpCoffee" xml:space="preserve">
<value>8. Coffee</value>
</data>
<data name="HelpCoffeeDescription" xml:space="preserve">
<value>Keep in mind that this is my hobby project. It was created for my inner needs and I believe it may be useful to others as well. I do not receive any compensation for creating and maintaining this project. If you want to support the development or thank me, you can buy me a coffee.</value>
</data>
<data name="HelpConnect" xml:space="preserve">
<value>1. How to connect to the scale</value>
</data>
<data name="HelpConnectDescription" xml:space="preserve">
<value>Set the Bluetooth address of the scale in settings. Set the correct age/height/gender values. Measure yourself. The scale is active for up to 15 minutes after measurement.</value>
</data>
<data name="HelpConnectDescription2" xml:space="preserve">
<value>Bluetooth address can be found in Zepp Life > Profile > My devices > Mi Body Composition Scale > Bluetooth address (hold to copy)</value>
</data>
<data name="HelpExternalApi" xml:space="preserve">
<value>5. External Api</value>
</data>
<data name="HelpExternalApiDescription" xml:space="preserve">
<value>External API is used as a proxy for older Android phones (9 or lower). The default address is https://frog01-20364.wykr.es/. You can host your own version of the API and this app will send the data to your system instead of Garmin. Check out the project repository for more information.</value>
</data>
<data name="HelpFeedback" xml:space="preserve">
<value>7. Feedback & Contact</value>
</data>
<data name="HelpFeedbackDescription" xml:space="preserve">
<value>If you found a bug, need a feature or have an idea, share it with me at the project repository.</value>
</data>
<data name="HelpGarminAndXiaomi" xml:space="preserve">
<value>6. Garmin and Xiaomi</value>
</data>
<data name="HelpGarminAndXiaomiDescription" xml:space="preserve">
<value>This application is an open source community project and I have no affiliation with Garmin or Xiaomi. You use it at your own risk. You can always check out the source code on Github.</value>
</data>
<data name="HelpHowItWorks" xml:space="preserve">
<value>2. How It works</value>
</data>
<data name="HelpHowItWorksDescription" xml:space="preserve">
<value>This App pass your data, email and password directly to Garmin Cloud or via external API server. The API does not store or log anything, it's just a middleware between this App and Garmin services.</value>
</data>
<data name="HelpStrangeResults" xml:space="preserve">
<value>3. Strange results? (Like 10kg only)</value>
</data>
<data name="HelpStrangeResultsDescription" xml:space="preserve">
<value>If you have the Mi Body Composition Scale 2. Disable the 'Weight small object' option in Zepp Life</value>
</data>
<data name="HelpZeppLifeDriference" xml:space="preserve">
<value>4. Results different from Zepp Life</value>
</data>
<data name="HelpZeppLifeDriferenceDescription" xml:space="preserve">
<value>Please check the age/height/gender parameters - should be identical in both apps. But even then, the values may be slightly different because we do not use the exact algorithm used by Xiaomi, but an alternative open source algorithm.</value>
</data>
<data name="IdealWeightKg" xml:space="preserve">
<value>Ideal Weight (Kg):</value>
</data>
<data name="IdealWeightLbs" xml:space="preserve">
<value>Ideal Weight (Lbs):</value>
</data>
<data name="Male" xml:space="preserve">
<value>Male</value>
</data>
<data name="MFACode" xml:space="preserve">
<value>MFA Code</value>
</data>
<data name="MiBodyCompositionScale" xml:space="preserve">
<value>Mi Body Composition Scale 1 / 2</value>
</data>
<data name="MiScale" xml:space="preserve">
<value>Mi Scale</value>
</data>
<data name="MiScaleData" xml:space="preserve">
<value>Mi Scale Data</value>
</data>
<data name="MiScaleExporter" xml:space="preserve">
<value>Mi Scale Exporter</value>
</data>
<data name="MiSmartScale" xml:space="preserve">
<value>Mi Smart Scale</value>
</data>
<data name="MuscleMassAsPercentage" xml:space="preserve">
<value>Muscle mass as %</value>
</data>
<data name="MuscleMassKg" xml:space="preserve">
<value>Muscle Mass (Kg)</value>
</data>
<data name="MuscleMassLbs" xml:space="preserve">
<value>Muscle Mass (Lbs)</value>
</data>
<data name="MuscleMassPer" xml:space="preserve">
<value>Muscle Mass (%)</value>
</data>
<data name="NotFound" xml:space="preserve">
<value>Not found</value>
</data>
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="OneClickScanUpload" xml:space="preserve">
<value>One click - Scan & Upload</value>
</data>
<data name="OpenHelp" xml:space="preserve">
<value>Open Help</value>
</data>
<data name="Password" xml:space="preserve">
<value>Password</value>
</data>
<data name="PermissionBluetoothRequired" xml:space="preserve">
<value>Permission to use Bluetooth is required to scan.</value>
</data>
<data name="PermissionLocationRequired" xml:space="preserve">
<value>Permission to use Location (Bluetooth) is required to scan.</value>
</data>
<data name="BluetoothDisabled" xml:space="preserve">
<value>Bluetooth is disabled. Please enable Bluetooth to scan for your Mi Scale.</value>
</data>
<data name="Problem" xml:space="preserve">
<value>Problem</value>
</data>
<data name="ProteinPercent" xml:space="preserve">
<value>Protein (%):</value>
</data>
<data name="ResetToDefault" xml:space="preserve">
<value>Reset to Default</value>
</data>
<data name="Response" xml:space="preserve">
<value>Response</value>
</data>
<data name="ScaleModel" xml:space="preserve">
<value>Scale Model</value>
</data>
<data name="ScaleSettings" xml:space="preserve">
<value>Scale Settings</value>
</data>
<data name="Scanning" xml:space="preserve">
<value>Scanning...</value>
</data>
<data name="Settings" xml:space="preserve">
<value>Settings</value>
</data>
<data name="SettingsHideAds" xml:space="preserve">
<value>Hide Ads Banner</value>
</data>
<data name="Sex" xml:space="preserve">
<value>Sex</value>
</data>
<data name="ShowDebug" xml:space="preserve">
<value>Show Debug Info during scan</value>
</data>
<data name="Start" xml:space="preserve">
<value>Start</value>
</data>
<data name="StopMeasure" xml:space="preserve">
<value>Stop Measure</value>
</data>
<data name="TimeOfMeasurement" xml:space="preserve">
<value>Time of measurement</value>
</data>
<data name="Uploaded" xml:space="preserve">
<value>Uploaded</value>
</data>
<data name="Uploading" xml:space="preserve">
<value>Uploading...</value>
</data>
<data name="UploadToGarminCloud" xml:space="preserve">
<value>Upload to Garmin Cloud</value>
</data>
<data name="UseExternalAPI" xml:space="preserve">
<value>Use External API</value>
</data>
<data name="ValuesThatWillNotBeSentToTheCloud" xml:space="preserve">
<value>Values that will not be sent to the cloud:</value>
</data>
<data name="VisceralFat" xml:space="preserve">
<value>Visceral fat</value>
</data>
<data name="VisitProjectRepository" xml:space="preserve">
<value>Visit the project repository</value>
</data>
<data name="WaterPercent" xml:space="preserve">
<value>Water (%)</value>
</data>
<data name="WeightKg" xml:space="preserve">
<value>Weight (Kg)</value>
</data>
<data name="WeightLbs" xml:space="preserve">
<value>Weight (Lbs)</value>
</data>
</root>
================================================
FILE: src/MiScaleExporter.MAUI/Resources/Raw/AboutAssets.txt
================================================
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories). Deployment of the asset to your application
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
These files will be deployed with you package and will be accessible using Essentials:
async Task LoadMauiAsset()
{
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
using var reader = new StreamReader(stream);
var contents = reader.ReadToEnd();
}
================================================
FILE: src/MiScaleExporter.MAUI/Resources/Styles/Colors.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Color x:Key="Primary">#007CC3</Color>
<Color x:Key="Secondary">#DFD8F7</Color>
<Color x:Key="Tertiary">#004b76</Color>
<Color x:Key="White">White</Color>
<Color x:Key="Black">Black</Color>
<Color x:Key="Gray100">#E1E1E1</Color>
<Color x:Key="Gray200">#C8C8C8</Color>
<Color x:Key="Gray300">#ACACAC</Color>
<Color x:Key="Gray400">#919191</Color>
<Color x:Key="Gray500">#6E6E6E</Color>
<Color x:Key="Gray600">#404040</Color>
<Color x:Key="Gray900">#212121</Color>
<Color x:Key="Gray950">#141414</Color>
<Color x:Key="Gray">#6E6E6E</Color>
<Color x:Key="DarkRed">DarkRed</Color>
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}" />
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}" />
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}" />
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}" />
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}" />
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}" />
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}" />
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}" />
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}" />
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}" />
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}" />
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}" />
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}" />
<Color x:Key="Yellow100Accent">#F7B548</Color>
<Color x:Key="Yellow200Accent">#FFD590</Color>
<Color x:Key="Yellow300Accent">#FFE5B9</Color>
<Color x:Key="Cyan100Accent">#28C2D1</Color>
<Color x:Key="Cyan200Accent">#7BDDEF</Color>
<Color x:Key="Cyan300Accent">#C3F2F4</Color>
<Color x:Key="Blue100Accent">#3E8EED</Color>
<Color x:Key="Blue200Accent">#72ACF1</Color>
<Color x:Key="Blue300Accent">#A7CBF6</Color>
</ResourceDictionary>
================================================
FILE: src/MiScaleExporter.MAUI/Resources/Styles/Styles.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Style TargetType="ActivityIndicator">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="IndicatorView">
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}" />
</Style>
<Style TargetType="Border">
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="StrokeShape" Value="Rectangle" />
<Setter Property="StrokeThickness" Value="1" />
</Style>
<Style TargetType="BoxView">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Primary}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="14,10" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="DatePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Editor">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Entry">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Frame">
<Setter Property="HasShadow" Value="False" />
<Setter Property="BorderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="CornerRadius" Value="8" />
</Style>
<Style TargetType="ImageButton">
<Setter Property="Opacity" Value="1" />
<Setter Property="BorderColor" Value="Transparent" />
<Setter Property="BorderWidth" Value="0" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Opacity" Value="0.5" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ListView">
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Picker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ProgressBar">
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RefreshView">
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="SearchBar">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SearchHandler">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Shadow">
<Setter Property="Radius" Value="15" />
<Setter Property="Opacity" Value="0.5" />
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Offset" Value="10,10" />
</Style>
<Style TargetType="Slider">
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SwipeItem">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Switch">
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="T
gitextract_nz2lm8kb/
├── .gitignore
├── .idea/
│ ├── .idea.MiScaleExporter/
│ │ └── .idea/
│ │ ├── .name
│ │ ├── encodings.xml
│ │ ├── indexLayout.xml
│ │ ├── misc.xml
│ │ ├── projectSettingsUpdater.xml
│ │ └── vcs.xml
│ └── .idea.miscale2garmin/
│ └── .idea/
│ ├── .gitignore
│ ├── .name
│ ├── encodings.xml
│ ├── indexLayout.xml
│ ├── misc.xml
│ └── vcs.xml
├── LICENSE
├── MiScaleExporter.sln
├── README.md
├── docs/
│ ├── _config.yml
│ ├── _includes/
│ │ ├── head-custom-google-analytics.html
│ │ └── head-custom.html
│ ├── _layouts/
│ │ └── default.html
│ ├── _sass/
│ │ ├── cayman.scss
│ │ ├── jekyll-theme-cayman.scss
│ │ ├── normalize.scss
│ │ ├── rouge-github.scss
│ │ └── variables.scss
│ └── index.md
└── src/
└── MiScaleExporter.MAUI/
├── App.xaml
├── App.xaml.cs
├── AppShell.xaml
├── AppShell.xaml.cs
├── Behaviors/
│ ├── NumericDoubleValidationBehavior.cs
│ └── NumericIntValidationBehavior.cs
├── Controls/
│ ├── FlyoutFooter.xaml
│ ├── FlyoutFooter.xaml.cs
│ ├── FlyoutHeader.xaml
│ └── FlyoutHeader.xaml.cs
├── Converters/
│ └── InvertedBoolConverter.cs
├── MauiProgram.cs
├── MiScaleExporter.MAUI.csproj
├── Models/
│ ├── BodyComposition.cs
│ ├── GarminApiResponse.cs
│ ├── GarminBodyCompositionRequest.cs
│ ├── GarminExternalApiResponse.cs
│ ├── GarminFitFileCreationResult.cs
│ ├── GarminUploadResult.cs
│ ├── PreferencesKeys.cs
│ ├── ScaleMeasurement.cs
│ ├── ScaleType.cs
│ ├── SettingKeys.cs
│ ├── Sex.cs
│ └── User.cs
├── Permission/
│ ├── BluetoothConnectPermission.cs
│ └── IBluetoothConnectPermission.cs
├── Platforms/
│ ├── Android/
│ │ ├── AndroidManifest.xml
│ │ ├── MainActivity.cs
│ │ ├── MainApplication.cs
│ │ └── Resources/
│ │ └── values/
│ │ ├── colors.xml
│ │ └── styles.xml
│ ├── MacCatalyst/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── Tizen/
│ │ ├── Main.cs
│ │ └── tizen-manifest.xml
│ ├── Windows/
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── Package.appxmanifest
│ │ └── app.manifest
│ └── iOS/
│ ├── AppDelegate.cs
│ ├── Info.plist
│ └── Program.cs
├── Properties/
│ └── launchSettings.json
├── Resources/
│ ├── Fonts/
│ │ ├── FontAwesome6Regular.otf
│ │ └── FontAwesome6Solid.otf
│ ├── Localization/
│ │ ├── AppSnippets.Designer.cs
│ │ ├── AppSnippets.pl.resx
│ │ └── AppSnippets.resx
│ ├── Raw/
│ │ └── AboutAssets.txt
│ └── Styles/
│ ├── Colors.xaml
│ └── Styles.xaml
├── Services/
│ ├── DataInterpreter.cs
│ ├── GarminService.cs
│ ├── IDataInterpreter.cs
│ ├── IGarminService.cs
│ ├── ILogService.cs
│ ├── IScale.cs
│ ├── LogService.cs
│ └── Scale.cs
├── Utils/
│ └── DoubleValueParser.cs
├── ViewModels/
│ ├── AboutViewModel.cs
│ ├── BaseViewModel.cs
│ ├── FormViewModel.cs
│ ├── IFormViewModel.cs
│ ├── IScaleViewModel.cs
│ ├── ISettingsViewModel.cs
│ ├── ScaleViewModel.cs
│ └── SettingsViewModel.cs
└── Views/
├── AboutPage.xaml
├── AboutPage.xaml.cs
├── FormPage.xaml
├── FormPage.xaml.cs
├── HelpPage.xaml
├── HelpPage.xaml.cs
├── ScalePage.xaml
├── ScalePage.xaml.cs
├── SettingsPage.xaml
└── SettingsPage.xaml.cs
SYMBOL INDEX (196 symbols across 53 files)
FILE: src/MiScaleExporter.MAUI/App.xaml.cs
class App (line 14) | public partial class App : Application
method App (line 18) | public App()
method CreateWindow (line 25) | protected override Window CreateWindow(IActivationState activationState)
method OnStart (line 37) | protected override void OnStart()
method AutofacInit (line 44) | protected void AutofacInit()
FILE: src/MiScaleExporter.MAUI/AppShell.xaml.cs
class AppShell (line 3) | public partial class AppShell : Shell
method AppShell (line 5) | public AppShell()
method OnMenuItemClicked (line 9) | private async void OnMenuItemClicked(object sender, EventArgs e)
FILE: src/MiScaleExporter.MAUI/Behaviors/NumericDoubleValidationBehavior.cs
class NumericDoubleValidationBehavior (line 8) | public class NumericDoubleValidationBehavior : Behavior<Entry>
method OnAttachedTo (line 10) | protected override void OnAttachedTo(Entry entry)
method OnDetachingFrom (line 16) | protected override void OnDetachingFrom(Entry entry)
method OnEntryTextChanged (line 22) | void OnEntryTextChanged(object sender, TextChangedEventArgs args)
FILE: src/MiScaleExporter.MAUI/Behaviors/NumericIntValidationBehavior.cs
class NumericIntValidationBehavior (line 5) | public class NumericIntValidationBehavior : Behavior<Entry>
method OnAttachedTo (line 7) | protected override void OnAttachedTo(Entry entry)
method OnDetachingFrom (line 13) | protected override void OnDetachingFrom(Entry entry)
method OnEntryTextChanged (line 19) | void OnEntryTextChanged(object sender, TextChangedEventArgs args)
FILE: src/MiScaleExporter.MAUI/Controls/FlyoutFooter.xaml.cs
class FlyoutFooter (line 3) | public partial class FlyoutFooter : ContentView
method FlyoutFooter (line 5) | public FlyoutFooter()
FILE: src/MiScaleExporter.MAUI/Controls/FlyoutHeader.xaml.cs
class FlyoutHeader (line 3) | public partial class FlyoutHeader : ContentView
method FlyoutHeader (line 5) | public FlyoutHeader()
FILE: src/MiScaleExporter.MAUI/Converters/InvertedBoolConverter.cs
class InvertedBoolConverter (line 5) | public class InvertedBoolConverter : IValueConverter
method Convert (line 7) | public object Convert(object value, Type targetType, object parameter,...
method ConvertBack (line 16) | public object ConvertBack(object value, Type targetType, object parame...
FILE: src/MiScaleExporter.MAUI/MauiProgram.cs
class MauiProgram (line 7) | public static class MauiProgram
method CreateMauiApp (line 9) | public static MauiApp CreateMauiApp()
FILE: src/MiScaleExporter.MAUI/Models/BodyComposition.cs
class BodyComposition (line 7) | public class BodyComposition
method BodyComposition (line 29) | public BodyComposition()
FILE: src/MiScaleExporter.MAUI/Models/GarminApiResponse.cs
class GarminApiResponse (line 3) | public class GarminApiResponse
FILE: src/MiScaleExporter.MAUI/Models/GarminBodyCompositionRequest.cs
type GarminBodyCompositionRequest (line 3) | public record GarminBodyCompositionRequest
FILE: src/MiScaleExporter.MAUI/Models/GarminExternalApiResponse.cs
type GarminExternalApiResponse (line 5) | public record GarminExternalApiResponse
FILE: src/MiScaleExporter.MAUI/Models/GarminFitFileCreationResult.cs
class GarminFitFileCreationResult (line 3) | public class GarminFitFileCreationResult
FILE: src/MiScaleExporter.MAUI/Models/GarminUploadResult.cs
type GarminUploadResult (line 5) | public record GarminUploadResult
FILE: src/MiScaleExporter.MAUI/Models/PreferencesKeys.cs
class PreferencesKeys (line 3) | public static class PreferencesKeys
FILE: src/MiScaleExporter.MAUI/Models/ScaleMeasurement.cs
class ScaleMeasurement (line 10) | public class ScaleMeasurement : INotifyPropertyChanged
method ScaleMeasurement (line 13) | private ScaleMeasurement() { }
FILE: src/MiScaleExporter.MAUI/Models/ScaleType.cs
type ScaleType (line 7) | public enum ScaleType : byte
FILE: src/MiScaleExporter.MAUI/Models/SettingKeys.cs
class SettingKeys (line 3) | public static class SettingKeys
FILE: src/MiScaleExporter.MAUI/Models/Sex.cs
type Sex (line 3) | public enum Sex : byte
FILE: src/MiScaleExporter.MAUI/Models/User.cs
class User (line 7) | public class User
FILE: src/MiScaleExporter.MAUI/Permission/BluetoothConnectPermission.cs
class BluetoothConnectPermission (line 8) | public class BluetoothConnectPermission : Permissions.BasePlatformPermis...
FILE: src/MiScaleExporter.MAUI/Permission/IBluetoothConnectPermission.cs
type IBluetoothConnectPermission (line 4) | public interface IBluetoothConnectPermission
method CheckStatusAsync (line 6) | Task<PermissionStatus> CheckStatusAsync();
method RequestAsync (line 7) | Task<PermissionStatus> RequestAsync();
FILE: src/MiScaleExporter.MAUI/Platforms/Android/MainActivity.cs
class MainActivity (line 10) | [Activity(Label = "MiScale Exporter", Theme = "@style/Maui.SplashTheme",...
method OnCreate (line 13) | protected override void OnCreate(Bundle savedInstanceState)
method OnRequestPermissionsResult (line 21) | public override void OnRequestPermissionsResult(int requestCode, strin...
FILE: src/MiScaleExporter.MAUI/Platforms/Android/MainApplication.cs
class MainApplication (line 6) | [Application]
method MainApplication (line 9) | public MainApplication(IntPtr handle, JniHandleOwnership ownership)
method CreateMauiApp (line 14) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: src/MiScaleExporter.MAUI/Platforms/MacCatalyst/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateMauiApp (line 8) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: src/MiScaleExporter.MAUI/Platforms/MacCatalyst/Program.cs
class Program (line 6) | public class Program
method Main (line 9) | static void Main(string[] args)
FILE: src/MiScaleExporter.MAUI/Platforms/Tizen/Main.cs
class Program (line 7) | internal class Program : MauiApplication
method CreateMauiApp (line 9) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
method Main (line 11) | static void Main(string[] args)
FILE: src/MiScaleExporter.MAUI/Platforms/Windows/App.xaml.cs
class App (line 11) | public partial class App : MauiWinUIApplication
method App (line 17) | public App()
method CreateMauiApp (line 22) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: src/MiScaleExporter.MAUI/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateMauiApp (line 8) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: src/MiScaleExporter.MAUI/Platforms/iOS/Program.cs
class Program (line 6) | public class Program
method Main (line 9) | static void Main(string[] args)
FILE: src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.Designer.cs
class AppSnippets (line 22) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resource...
method AppSnippets (line 31) | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Mic...
FILE: src/MiScaleExporter.MAUI/Services/DataInterpreter.cs
class DataInterpreter (line 6) | public class DataInterpreter : IDataInterpreter
method ValidateAesKey (line 8) | private void ValidateAesKey(string aesKey)
method ValidateBluetoothAddress (line 15) | private void ValidateBluetoothAddress(string btAddress)
method ComputeData (line 23) | public BodyComposition ComputeData(byte[] data, User _user, string btA...
method GetWeight (line 149) | private double GetWeight(byte[] data)
FILE: src/MiScaleExporter.MAUI/Services/GarminService.cs
class GarminService (line 20) | public class GarminService : IGarminService
method GarminService (line 27) | public GarminService(ILogService logService)
method UploadAsync (line 60) | public async Task<GarminApiResponse> UploadAsync(BodyComposition bodyC...
method UploadViaDirectCallToGarminAsync (line 80) | private async Task<GarminApiResponse> UploadViaDirectCallToGarminAsync...
method GenerateFitFileAsync (line 147) | public async Task<GarminFitFileCreationResult> GenerateFitFileAsync(Bo...
method UploadViaExternalAPIAsync (line 199) | private async Task<GarminApiResponse> UploadViaExternalAPIAsync(BodyCo...
method UploadToGarminCloud (line 228) | private async Task<GarminApiResponse> UploadToGarminCloud(GarminBodyCo...
method PostAsync (line 273) | private async Task<HttpResponseMessage> PostAsync(string requestUri, H...
FILE: src/MiScaleExporter.MAUI/Services/IDataInterpreter.cs
type IDataInterpreter (line 5) | public interface IDataInterpreter
method ComputeData (line 7) | BodyComposition ComputeData(byte[] data, User _user, string btAddress);
FILE: src/MiScaleExporter.MAUI/Services/IGarminService.cs
type IGarminService (line 8) | public interface IGarminService
method UploadAsync (line 10) | Task<GarminApiResponse> UploadAsync(BodyComposition bodyComposition, D...
method GenerateFitFileAsync (line 11) | Task<GarminFitFileCreationResult> GenerateFitFileAsync(BodyComposition...
FILE: src/MiScaleExporter.MAUI/Services/ILogService.cs
type ILogService (line 5) | public interface ILogService
method LogDebug (line 7) | void LogDebug(string message);
method LogError (line 8) | void LogError(string message);
method LogFatal (line 9) | void LogFatal(string message);
method LogInfo (line 10) | void LogInfo(string message);
method LogWarning (line 11) | void LogWarning(string message);
FILE: src/MiScaleExporter.MAUI/Services/IScale.cs
type IScale (line 9) | public interface IScale
method GetBodyCompositonAsync (line 12) | Task<BodyComposition> GetBodyCompositonAsync(string scaleAddress, User...
method CancelSearchAsync (line 14) | Task CancelSearchAsync();
method StopSearch (line 16) | void StopSearch();
FILE: src/MiScaleExporter.MAUI/Services/LogService.cs
class LogService (line 7) | public class LogService : ILogService
method LogService (line 14) | public LogService()
method LogDebug (line 18) | public void LogDebug(string message)
method LogError (line 22) | public void LogError(string message)
method LogFatal (line 28) | public void LogFatal(string message)
method LogInfo (line 35) | public void LogInfo(string message)
method LogWarning (line 41) | public void LogWarning(string message)
method CreateLogger (line 48) | public static LoggingConfiguration CreateLogger()
method GetLogs (line 76) | public static IList<string> GetLogs()
method GetErrorLogs (line 88) | public static IList<string> GetErrorLogs()
FILE: src/MiScaleExporter.MAUI/Services/Scale.cs
class Scale (line 9) | public class Scale : IScale
method Scale (line 36) | public Scale(ILogService logService, IDataInterpreter dataInterpreter)
method GetBodyCompositonAsync (line 46) | public async Task<BodyComposition> GetBodyCompositonAsync(string scale...
method DeviceAdvertided (line 63) | private void DeviceAdvertided(object s, DeviceEventArgs a)
method ProcessReceivedData (line 107) | private void ProcessReceivedData()
method BytesToHex (line 145) | public static string BytesToHex(byte[] bytes)
method SetPreviews (line 150) | private void SetPreviews(BodyComposition bodyCompositionCandidate)
method GetWeightScanningLabel (line 175) | private string GetWeightScanningLabel(double valueInKg, bool convertTo...
method GetScanData (line 180) | private BodyComposition GetScanData(IDevice device)
method CalculateBMIIfEmpty (line 206) | private void CalculateBMIIfEmpty()
method CancelSearchAsync (line 215) | public async Task CancelSearchAsync()
method StopSearch (line 237) | public void StopSearch()
method TimeOuted (line 253) | private void TimeOuted(object s, EventArgs e)
method StopAsync (line 259) | private async Task StopAsync()
FILE: src/MiScaleExporter.MAUI/Utils/DoubleValueParser.cs
class DoubleValueParser (line 11) | public static class DoubleValueParser
method IsValid (line 13) | public static bool IsValid(string value)
method CheckValue (line 26) | public static string CheckValue(string value)
method ParseValueFromUsersCulture (line 40) | public static double? ParseValueFromUsersCulture(string value)
method ParseDouble (line 63) | private static double? ParseDouble(string value)
FILE: src/MiScaleExporter.MAUI/ViewModels/AboutViewModel.cs
class AboutViewModel (line 8) | public class AboutViewModel : BaseViewModel
method AboutViewModel (line 10) | public AboutViewModel()
FILE: src/MiScaleExporter.MAUI/ViewModels/BaseViewModel.cs
class BaseViewModel (line 11) | public class BaseViewModel : INotifyPropertyChanged
method SetProperty (line 27) | protected bool SetProperty<T>(ref T backingStore, T value,
method OnPropertyChanged (line 42) | protected void OnPropertyChanged([CallerMemberName] string propertyNam...
method NotifyAllPropertiesChanged (line 52) | protected void NotifyAllPropertiesChanged()
FILE: src/MiScaleExporter.MAUI/ViewModels/FormViewModel.cs
class FormViewModel (line 14) | public class FormViewModel : BaseViewModel, IFormViewModel
method FormViewModel (line 20) | public FormViewModel(IGarminService garminService, IFileSaver fileSaver)
method LoadPreferencesAsync (line 37) | public async Task LoadPreferencesAsync()
method ValidateSave (line 61) | private bool ValidateSave()
method AutoUpload (line 67) | public void AutoUpload()
method OnUpload (line 76) | private async void OnUpload()
method OnGenerateFitFileAsync (line 121) | private async void OnGenerateFitFileAsync()
method OnCancelMFA (line 151) | private async void OnCancelMFA()
method PrepareRequest (line 160) | private BodyComposition PrepareRequest()
method LoadBodyComposition (line 188) | public void LoadBodyComposition()
method ConvertFromKg (line 409) | private double ConvertFromKg(double valueInKg)
method ConvertToKg (line 414) | private double ConvertToKg(double displayValue)
FILE: src/MiScaleExporter.MAUI/ViewModels/IFormViewModel.cs
type IFormViewModel (line 3) | public interface IFormViewModel
method LoadBodyComposition (line 5) | void LoadBodyComposition();
method LoadPreferencesAsync (line 6) | Task LoadPreferencesAsync();
method AutoUpload (line 8) | void AutoUpload();
FILE: src/MiScaleExporter.MAUI/ViewModels/IScaleViewModel.cs
type IScaleViewModel (line 8) | public interface IScaleViewModel
method CheckPreferencesAsync (line 10) | Task CheckPreferencesAsync();
method LoadPreferencesAsync (line 11) | Task LoadPreferencesAsync();
FILE: src/MiScaleExporter.MAUI/ViewModels/ISettingsViewModel.cs
type ISettingsViewModel (line 9) | public interface ISettingsViewModel
method SexRadioSetToMale (line 11) | void SexRadioSetToMale();
method SexRadioSetToFemale (line 12) | void SexRadioSetToFemale();
method ScaleTypeSetToBodyCompositionScale (line 13) | void ScaleTypeSetToBodyCompositionScale();
method ScaleTypeSetToMiscale (line 14) | void ScaleTypeSetToMiscale();
method ScaleTypeSetToS400 (line 15) | void ScaleTypeSetToS400();
method LoadPreferencesAsync (line 16) | Task LoadPreferencesAsync();
FILE: src/MiScaleExporter.MAUI/ViewModels/ScaleViewModel.cs
class ScaleViewModel (line 10) | public class ScaleViewModel : BaseViewModel, IScaleViewModel
method ScaleViewModel (line 23) | public ScaleViewModel(IScale scale, ILogService logService)
method CheckPreferencesAsync (line 33) | public async Task CheckPreferencesAsync()
method LoadPreferencesAsync (line 55) | public async Task LoadPreferencesAsync()
method OnScan (line 65) | private async void OnScan()
method CheckPermissions (line 70) | private async Task<bool> CheckPermissions()
method StartScan (line 119) | private async Task StartScan()
method OnStop (line 129) | private async void OnStop()
method OnCancel (line 148) | private async void OnCancel()
method GetLocationWhenInUsePermissionStatusAsync (line 154) | private async Task<PermissionStatus> GetLocationWhenInUsePermissionSta...
method GetLocationAlwaysPermissionStatusAsync (line 165) | private async Task<PermissionStatus> GetLocationAlwaysPermissionStatus...
method GetBluetoothPermissionStatusAsync (line 176) | private async Task<PermissionStatus> GetBluetoothPermissionStatusAsync()
FILE: src/MiScaleExporter.MAUI/ViewModels/SettingsViewModel.cs
class SettingsViewModel (line 10) | public class SettingsViewModel : BaseViewModel, ISettingsViewModel
method SettingsViewModel (line 12) | public SettingsViewModel()
method LoadPreferencesAsync (line 44) | public async Task LoadPreferencesAsync()
method ValidateProfile (line 90) | private bool ValidateProfile()
method SexRadioSetToMale (line 205) | public void SexRadioSetToMale()
method SexRadioSetToFemale (line 210) | public void SexRadioSetToFemale()
method ScaleTypeSetToBodyCompositionScale (line 215) | public void ScaleTypeSetToBodyCompositionScale()
method ScaleTypeSetToMiscale (line 220) | public void ScaleTypeSetToMiscale()
method ScaleTypeSetToS400 (line 225) | public void ScaleTypeSetToS400()
method CheckPreferences (line 231) | public void CheckPreferences()
method _clearTokens (line 444) | private void _clearTokens()
FILE: src/MiScaleExporter.MAUI/Views/AboutPage.xaml.cs
class AboutPage (line 13) | [XamlCompilation(XamlCompilationOptions.Compile)]
method AboutPage (line 16) | public AboutPage()
method OnAppearing (line 25) | protected override void OnAppearing()
FILE: src/MiScaleExporter.MAUI/Views/FormPage.xaml.cs
class FormPage (line 9) | [QueryProperty(nameof(AutoUpload), "autoUpload")]
method FormPage (line 14) | public FormPage()
method OnAppearing (line 23) | protected override async void OnAppearing()
FILE: src/MiScaleExporter.MAUI/Views/HelpPage.xaml.cs
class HelpPage (line 5) | public partial class HelpPage : ContentPage
method HelpPage (line 12) | public HelpPage()
FILE: src/MiScaleExporter.MAUI/Views/ScalePage.xaml.cs
class ScalePage (line 9) | public partial class ScalePage : ContentPage
method ScalePage (line 12) | public ScalePage()
method OnAppearing (line 21) | protected override async void OnAppearing()
FILE: src/MiScaleExporter.MAUI/Views/SettingsPage.xaml.cs
class SettingPage (line 12) | [XamlCompilation(XamlCompilationOptions.Compile)]
method SettingPage (line 16) | public SettingPage()
method SexRadioSetToMale (line 25) | private void SexRadioSetToMale(object sender, CheckedChangedEventArgs e)
method SexRadioSetToFemale (line 32) | private void SexRadioSetToFemale(object sender, CheckedChangedEventArg...
method ScaleTypeSetToBodyCompositionScale (line 39) | private void ScaleTypeSetToBodyCompositionScale(object sender, Checked...
method ScaleTypeSetToMiscale (line 47) | private void ScaleTypeSetToMiscale(object sender, CheckedChangedEventA...
method ScaleTypeSetToS400 (line 55) | private void ScaleTypeSetToS400(object sender, CheckedChangedEventArgs e)
method OnAppearing (line 64) | protected override async void OnAppearing()
Condensed preview — 106 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (338K chars).
[
{
"path": ".gitignore",
"chars": 9097,
"preview": "\n# Created by https://www.toptal.com/developers/gitignore/api/rider,visualstudio,visualstudiocode\n# Edit at https://www."
},
{
"path": ".idea/.idea.MiScaleExporter/.idea/.name",
"chars": 15,
"preview": "MiScaleExporter"
},
{
"path": ".idea/.idea.MiScaleExporter/.idea/encodings.xml",
"chars": 169,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"Encoding\" addBOMForNewFiles=\"with BOM un"
},
{
"path": ".idea/.idea.MiScaleExporter/.idea/indexLayout.xml",
"chars": 198,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"UserContentModel\">\n <attachedFolders "
},
{
"path": ".idea/.idea.MiScaleExporter/.idea/misc.xml",
"chars": 666,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"DesignSurface\">\n <option name=\"filePa"
},
{
"path": ".idea/.idea.MiScaleExporter/.idea/projectSettingsUpdater.xml",
"chars": 184,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"RiderProjectSettingsUpdater\">\n <optio"
},
{
"path": ".idea/.idea.MiScaleExporter/.idea/vcs.xml",
"chars": 180,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": ".idea/.idea.miscale2garmin/.idea/.gitignore",
"chars": 311,
"preview": "# Default ignored files\n/shelf/\n/workspace.xml\n# Rider ignored files\n/contentModel.xml\n/.idea.miscale2garmin.iml\n/.idea"
},
{
"path": ".idea/.idea.miscale2garmin/.idea/.name",
"chars": 14,
"preview": "miscale2garmin"
},
{
"path": ".idea/.idea.miscale2garmin/.idea/encodings.xml",
"chars": 169,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"Encoding\" addBOMForNewFiles=\"with BOM un"
},
{
"path": ".idea/.idea.miscale2garmin/.idea/indexLayout.xml",
"chars": 198,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"UserContentModel\">\n <attachedFolders "
},
{
"path": ".idea/.idea.miscale2garmin/.idea/misc.xml",
"chars": 232,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"com.jetbrains.rider.android.RiderAndroid"
},
{
"path": ".idea/.idea.miscale2garmin/.idea/vcs.xml",
"chars": 180,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "MiScaleExporter.sln",
"chars": 2497,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.3211"
},
{
"path": "README.md",
"chars": 5012,
"preview": "# mi-scale-exporter\n\nMobile App to export data from Mi Body Composition Scale (works with Mi Scale too) and upload it to"
},
{
"path": "docs/_config.yml",
"chars": 198,
"preview": "title: MiScale Exporter\ndescription: Mobile App to export data from Mi Body Composition Scale and upload it to Garmin Co"
},
{
"path": "docs/_includes/head-custom-google-analytics.html",
"chars": 595,
"preview": "{% if site.google_analytics %}\n<script>\n (function (i, s, o, g, r, a, m) {\n i['GoogleAnalyticsObject'] = r;\n (i[r"
},
{
"path": "docs/_includes/head-custom.html",
"chars": 346,
"preview": "<!-- start custom head snippets, customize with your own _includes/head-custom.html file -->\n\n<!-- Setup Google Analytic"
},
{
"path": "docs/_layouts/default.html",
"chars": 2053,
"preview": "<!DOCTYPE html>\n<html lang=\"{{ site.lang | default: \"en-US\" }}\">\n <head>\n <meta charset=\"UTF-8\">\n\n{% seo %}\n <lin"
},
{
"path": "docs/_sass/cayman.scss",
"chars": 170,
"preview": "// Placeholder file. If your site uses\n// @import \"{{ site.theme }}\";\n// Then using this theme with jekyll-remote-th"
},
{
"path": "docs/_sass/jekyll-theme-cayman.scss",
"chars": 6198,
"preview": "@import \"normalize\";\n@import \"rouge-github\";\n@import \"variables\";\n@import url('https://fonts.googleapis.com/css?family=O"
},
{
"path": "docs/_sass/normalize.scss",
"chars": 7698,
"preview": "/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Pre"
},
{
"path": "docs/_sass/rouge-github.scss",
"chars": 2902,
"preview": ".highlight table td { padding: 5px; }\n.highlight table pre { margin: 0; }\n.highlight .cm {\n color: #999988;\n font-styl"
},
{
"path": "docs/_sass/variables.scss",
"chars": 580,
"preview": "// Breakpoints\n$large-breakpoint: 64em !default;\n$medium-breakpoint: 42em !default;\n\n// Headers\n$header-heading-color: #"
},
{
"path": "docs/index.md",
"chars": 7765,
"preview": "---\nlayout: default\n---\n\nMobile App to export data from Xiaomi Scales:\n\n- Mi Smart Scale\n- [Mi Body Composition Scale 1 "
},
{
"path": "src/MiScaleExporter.MAUI/App.xaml",
"chars": 802,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<Application\n x:Class=\"MiScaleExporter.MAUI.App\"\n xmlns=\"http://schemas.m"
},
{
"path": "src/MiScaleExporter.MAUI/App.xaml.cs",
"chars": 2363,
"preview": "using Autofac;\nusing Autofac.Extras.CommonServiceLocator;\nusing CommonServiceLocator;\nusing MiScaleExporter.Models;\nusi"
},
{
"path": "src/MiScaleExporter.MAUI/AppShell.xaml",
"chars": 7119,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<Shell\n x:Class=\"MiScaleExporter.MAUI.AppShell\"\n xmlns=\"http://schemas.mic"
},
{
"path": "src/MiScaleExporter.MAUI/AppShell.xaml.cs",
"chars": 312,
"preview": "namespace MiScaleExporter.MAUI\n{\n public partial class AppShell : Shell\n {\n public AppShell()\n {\n "
},
{
"path": "src/MiScaleExporter.MAUI/Behaviors/NumericDoubleValidationBehavior.cs",
"chars": 829,
"preview": "\n\n\nusing MiScaleExporter.MAUI.Utils;\n\nnamespace MiScaleExporter.MAUI.Behaviors;\n\npublic class NumericDoubleValidationBe"
},
{
"path": "src/MiScaleExporter.MAUI/Behaviors/NumericIntValidationBehavior.cs",
"chars": 784,
"preview": " \n\nnamespace MiScaleExporter.MAUI.Behaviors;\n\npublic class NumericIntValidationBehavior : Behavior<Entry>\n{\n protect"
},
{
"path": "src/MiScaleExporter.MAUI/Controls/FlyoutFooter.xaml",
"chars": 549,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<ContentView\n x:Class=\"MiScaleExporter.Controls.FlyoutFooter\"\n xmlns=\"http"
},
{
"path": "src/MiScaleExporter.MAUI/Controls/FlyoutFooter.xaml.cs",
"chars": 142,
"preview": "namespace MiScaleExporter.Controls;\n\npublic partial class FlyoutFooter : ContentView\n{\n\tpublic FlyoutFooter()\n\t{\n\t\tIniti"
},
{
"path": "src/MiScaleExporter.MAUI/Controls/FlyoutHeader.xaml",
"chars": 461,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<ContentView xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n "
},
{
"path": "src/MiScaleExporter.MAUI/Controls/FlyoutHeader.xaml.cs",
"chars": 142,
"preview": "namespace MiScaleExporter.Controls;\n\npublic partial class FlyoutHeader : ContentView\n{\n\tpublic FlyoutHeader()\n\t{\n\t\tIniti"
},
{
"path": "src/MiScaleExporter.MAUI/Converters/InvertedBoolConverter.cs",
"chars": 571,
"preview": "using System.Globalization;\n\nnamespace MiScaleExporter.MAUI.Converters;\n\npublic class InvertedBoolConverter : IValueConv"
},
{
"path": "src/MiScaleExporter.MAUI/MauiProgram.cs",
"chars": 925,
"preview": "using CommunityToolkit.Maui;\nusing Plugin.AdMob;\nusing Plugin.AdMob.Configuration;\n\nnamespace MiScaleExporter.MAUI\n{\n "
},
{
"path": "src/MiScaleExporter.MAUI/MiScaleExporter.MAUI.csproj",
"chars": 6407,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFrameworks>net9.0-android</TargetFrameworks>\n\t\t<!-- Uncomm"
},
{
"path": "src/MiScaleExporter.MAUI/Models/BodyComposition.cs",
"chars": 1182,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MiScaleExporter.Models\n{\n public class"
},
{
"path": "src/MiScaleExporter.MAUI/Models/GarminApiResponse.cs",
"chars": 333,
"preview": "namespace MiScaleExporter.Models;\n\npublic class GarminApiResponse\n{\n public bool IsSuccess { get; set; }\n public "
},
{
"path": "src/MiScaleExporter.MAUI/Models/GarminBodyCompositionRequest.cs",
"chars": 769,
"preview": "namespace MiScaleExporter.Models;\n\npublic record GarminBodyCompositionRequest\n{\n public long TimeStamp { get; set; }"
},
{
"path": "src/MiScaleExporter.MAUI/Models/GarminExternalApiResponse.cs",
"chars": 242,
"preview": "using YetAnotherGarminConnectClient.Dto;\n\nnamespace MiScaleExporter.Models\n{\n public record GarminExternalApiRespons"
},
{
"path": "src/MiScaleExporter.MAUI/Models/GarminFitFileCreationResult.cs",
"chars": 207,
"preview": "namespace MiScaleExporter.Models;\n\n public class GarminFitFileCreationResult\n {\n public bool IsSuccess { get; "
},
{
"path": "src/MiScaleExporter.MAUI/Models/GarminUploadResult.cs",
"chars": 517,
"preview": "using YetAnotherGarminConnectClient.Dto;\n\nnamespace MiScaleExporter.Models\n{\n public record GarminUploadResult\n {"
},
{
"path": "src/MiScaleExporter.MAUI/Models/PreferencesKeys.cs",
"chars": 1399,
"preview": "namespace MiScaleExporter.Models;\n\npublic static class PreferencesKeys\n{\n public static string UserAge = \"UserAge\";\n"
},
{
"path": "src/MiScaleExporter.MAUI/Models/ScaleMeasurement.cs",
"chars": 2038,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Text;\nusin"
},
{
"path": "src/MiScaleExporter.MAUI/Models/ScaleType.cs",
"chars": 231,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MiScaleExporter.Models\n{\n public enum "
},
{
"path": "src/MiScaleExporter.MAUI/Models/SettingKeys.cs",
"chars": 147,
"preview": "namespace MiScaleExporter.Models;\n\npublic static class SettingKeys\n{\n public static string ApiServerAddress = \"https"
},
{
"path": "src/MiScaleExporter.MAUI/Models/Sex.cs",
"chars": 115,
"preview": "namespace MiScaleExporter.Models\n{\n public enum Sex : byte\n {\n Male = 0,\n Female = 1,\n }\n}\n"
},
{
"path": "src/MiScaleExporter.MAUI/Models/User.cs",
"chars": 347,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MiScaleExporter.Models\n{\n public class"
},
{
"path": "src/MiScaleExporter.MAUI/Permission/BluetoothConnectPermission.cs",
"chars": 614,
"preview": "using MiScaleExporter.Permission;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MiScale"
},
{
"path": "src/MiScaleExporter.MAUI/Permission/IBluetoothConnectPermission.cs",
"chars": 202,
"preview": "\nnamespace MiScaleExporter.Permission\n{\n public interface IBluetoothConnectPermission\n {\n Task<PermissionS"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Android/AndroidManifest.xml",
"chars": 1951,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" android:ver"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Android/MainActivity.cs",
"chars": 1224,
"preview": "using Android.App;\nusing Android.Content.PM;\nusing Android.OS;\nusing Android.Runtime;\nusing MiScaleExporter.Droid;\nusin"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Android/MainApplication.cs",
"chars": 377,
"preview": "using Android.App;\nusing Android.Runtime;\n\nnamespace MiScaleExporter.MAUI\n{\n [Application]\n public class MainAppl"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Android/Resources/values/colors.xml",
"chars": 258,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<color name=\"launcher_background\">#FFFFFF</color>\n <color name=\"c"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Android/Resources/values/styles.xml",
"chars": 1390,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<resources>\n\n <style name=\"MainTheme\" parent=\"MainTheme.Base\">\n </style>\n "
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/MacCatalyst/AppDelegate.cs",
"chars": 236,
"preview": "using Foundation;\n\nnamespace MiScaleExporter.MAUI\n{\n [Register(\"AppDelegate\")]\n public class AppDelegate : MauiUI"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/MacCatalyst/Info.plist",
"chars": 961,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/MacCatalyst/Program.cs",
"chars": 422,
"preview": "using ObjCRuntime;\nusing UIKit;\n\nnamespace MiScaleExporter.MAUI\n{\n public class Program\n {\n // This is the"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Tizen/Main.cs",
"chars": 366,
"preview": "using Microsoft.Maui;\nusing Microsoft.Maui.Hosting;\nusing System;\n\nnamespace MiScaleExporter.MAUI\n{\n internal class P"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Tizen/tizen-manifest.xml",
"chars": 747,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"maui-application-id-placeholder\" version=\"0.0.0\" api-version="
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Windows/App.xaml",
"chars": 322,
"preview": "<maui:MauiWinUIApplication\n x:Class=\"MiScaleExporter.MAUI.WinUI.App\"\n xmlns=\"http://schemas.microsoft.com/winfx/2"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Windows/App.xaml.cs",
"chars": 793,
"preview": "using Microsoft.UI.Xaml;\n\n// To learn more about WinUI, the WinUI project structure,\n// and more about our project temp"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Windows/Package.appxmanifest",
"chars": 1615,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Package\n xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows1"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/Windows/app.manifest",
"chars": 740,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n <asse"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/iOS/AppDelegate.cs",
"chars": 236,
"preview": "using Foundation;\n\nnamespace MiScaleExporter.MAUI\n{\n [Register(\"AppDelegate\")]\n public class AppDelegate : MauiUI"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/iOS/Info.plist",
"chars": 1001,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "src/MiScaleExporter.MAUI/Platforms/iOS/Program.cs",
"chars": 422,
"preview": "using ObjCRuntime;\nusing UIKit;\n\nnamespace MiScaleExporter.MAUI\n{\n public class Program\n {\n // This is the"
},
{
"path": "src/MiScaleExporter.MAUI/Properties/launchSettings.json",
"chars": 121,
"preview": "{\n \"profiles\": {\n \"Windows Machine\": {\n \"commandName\": \"MsixPackage\",\n \"nativeDebugging\": false\n }\n }\n"
},
{
"path": "src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.Designer.cs",
"chars": 32368,
"preview": "//------------------------------------------------------------------------------\n// <auto-generated>\n// This code w"
},
{
"path": "src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.pl.resx",
"chars": 17335,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/MiScaleExporter.MAUI/Resources/Localization/AppSnippets.resx",
"chars": 16948,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/MiScaleExporter.MAUI/Resources/Raw/AboutAssets.txt",
"chars": 639,
"preview": "Any raw assets you want to be deployed with your application can be placed in\nthis directory (and child directories). D"
},
{
"path": "src/MiScaleExporter.MAUI/Resources/Styles/Colors.xaml",
"chars": 2321,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<?xaml-comp compile=\"true\" ?>\n<ResourceDictionary xmlns=\"http://schemas.microso"
},
{
"path": "src/MiScaleExporter.MAUI/Resources/Styles/Styles.xaml",
"chars": 21914,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<?xaml-comp compile=\"true\" ?>\n<ResourceDictionary xmlns=\"http://schemas.microso"
},
{
"path": "src/MiScaleExporter.MAUI/Services/DataInterpreter.cs",
"chars": 6327,
"preview": "using MiScaleBodyComposition.Contracts;\nusing MiScaleExporter.Models;\n\nnamespace MiScaleExporter.Services\n{\n public "
},
{
"path": "src/MiScaleExporter.MAUI/Services/GarminService.cs",
"chars": 10853,
"preview": "using System;\nusing System.IO;\nusing System.Net;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Tex"
},
{
"path": "src/MiScaleExporter.MAUI/Services/IDataInterpreter.cs",
"chars": 201,
"preview": "using MiScaleExporter.Models;\n\nnamespace MiScaleExporter.Services\n{\n public interface IDataInterpreter\n {\n "
},
{
"path": "src/MiScaleExporter.MAUI/Services/IGarminService.cs",
"chars": 426,
"preview": "using System;\nusing System.Threading.Tasks;\nusing MiScaleExporter.Models;\nusing YetAnotherGarminConnectClient.Dto.Garmi"
},
{
"path": "src/MiScaleExporter.MAUI/Services/ILogService.cs",
"chars": 272,
"preview": "using System.Reflection;\n\nnamespace MiScaleExporter.Services;\n\npublic interface ILogService\n{\n void LogDebug(string "
},
{
"path": "src/MiScaleExporter.MAUI/Services/IScale.cs",
"chars": 411,
"preview": "using MiScaleExporter.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Threading"
},
{
"path": "src/MiScaleExporter.MAUI/Services/LogService.cs",
"chars": 2604,
"preview": "using NLog.Config;\nusing NLog.Targets;\nusing NLog;\n\nnamespace MiScaleExporter.Services;\n\npublic class LogService : ILog"
},
{
"path": "src/MiScaleExporter.MAUI/Services/Scale.cs",
"chars": 9408,
"preview": "using MiScaleExporter.Models;\nusing Plugin.BLE;\nusing Plugin.BLE.Abstractions.Contracts;\nusing Plugin.BLE.Abstractions."
},
{
"path": "src/MiScaleExporter.MAUI/Utils/DoubleValueParser.cs",
"chars": 1885,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Runtime.Com"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/AboutViewModel.cs",
"chars": 950,
"preview": "using MiScaleExporter.MAUI.Resources.Localization;\nusing System.Windows.Input;\n \n \n\nnamespace MiScaleExporter.MAUI.View"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/BaseViewModel.cs",
"chars": 1629,
"preview": "using MiScaleExporter.Models;\nusing MiScaleExporter.Services;\nusing System;\nusing System.Collections.Generic;\nusing Sys"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/FormViewModel.cs",
"chars": 15574,
"preview": "using CommunityToolkit.Maui.Alerts;\nusing CommunityToolkit.Maui.Storage;\nusing MiScaleExporter.MAUI;\nusing MiScaleExpor"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/IFormViewModel.cs",
"chars": 195,
"preview": "namespace MiScaleExporter.MAUI.ViewModels\n{\n public interface IFormViewModel\n {\n void LoadBodyComposition("
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/IScaleViewModel.cs",
"chars": 241,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n \n\nnamespace MiScaleExporter.MAUI.ViewModels\n{\n p"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/ISettingsViewModel.cs",
"chars": 447,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nna"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/ScaleViewModel.cs",
"chars": 7401,
"preview": "using MiScaleExporter.Models;\nusing MiScaleExporter.Services;\nusing MiScaleExporter.Permission;\nusing MiScaleExporter.M"
},
{
"path": "src/MiScaleExporter.MAUI/ViewModels/SettingsViewModel.cs",
"chars": 13971,
"preview": "using System;\nusing System.Windows.Input;\nusing MiScaleExporter.MAUI.Resources.Localization;\nusing MiScaleExporter.Mode"
},
{
"path": "src/MiScaleExporter.MAUI/Views/AboutPage.xaml",
"chars": 2998,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<ContentPage\n x:Class=\"MiScaleExporter.MAUI.Views.AboutPage\"\n xmlns=\"http"
},
{
"path": "src/MiScaleExporter.MAUI/Views/AboutPage.xaml.cs",
"chars": 791,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusi"
},
{
"path": "src/MiScaleExporter.MAUI/Views/FormPage.xaml",
"chars": 15183,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n\n<ContentPage\n x:Class=\"MiScaleExporter.MAUI.Views.FormPage\"\n xmlns=\"http"
},
{
"path": "src/MiScaleExporter.MAUI/Views/FormPage.xaml.cs",
"chars": 1065,
"preview": "\nusing Autofac;\n\nusing MiScaleExporter.MAUI.ViewModels;\nusing MiScaleExporter.Models;\n\nnamespace MiScaleExporter.MAUI.V"
},
{
"path": "src/MiScaleExporter.MAUI/Views/HelpPage.xaml",
"chars": 4740,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<ContentPage\n x:Class=\"MiScaleExporter.MAUI.Views.HelpPage\"\n xmlns=\"http:/"
},
{
"path": "src/MiScaleExporter.MAUI/Views/HelpPage.xaml.cs",
"chars": 795,
"preview": "using System.Windows.Input;\n\nnamespace MiScaleExporter.MAUI.Views;\n\npublic partial class HelpPage : ContentPage\n{\n pu"
},
{
"path": "src/MiScaleExporter.MAUI/Views/ScalePage.xaml",
"chars": 4049,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n\n<ContentPage\n x:Class=\"MiScaleExporter.MAUI.Views.ScalePage\"\n xmlns=\"htt"
},
{
"path": "src/MiScaleExporter.MAUI/Views/ScalePage.xaml.cs",
"chars": 722,
"preview": "\nusing Autofac;\nusing MiScaleExporter.Models;\nusing MiScaleExporter.MAUI.ViewModels;\n\n\nnamespace MiScaleExporter.MAUI.V"
},
{
"path": "src/MiScaleExporter.MAUI/Views/SettingsPage.xaml",
"chars": 17831,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<ContentPage\n x:Class=\"MiScaleExporter.MAUI.Views.SettingPage\"\n xmlns=\"ht"
},
{
"path": "src/MiScaleExporter.MAUI/Views/SettingsPage.xaml.cs",
"chars": 1827,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusi"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the lswiderski/mi-scale-exporter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 106 files (308.8 KB), approximately 73.0k tokens, and a symbol index with 196 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.