### Dynamic Theme and Resource Loading (JavaScript) Source: https://github.com/zreptil/nightscout-reporter/blob/master/web/index.template.html This JavaScript code snippet dynamically loads theme assets (images, CSS, manifest, favicon) for the Nightscout Reporter based on the current URL and local storage settings. It checks for 'beta' or 'watch' in the URL to adjust the ID and suffix, and attempts to retrieve theme preferences from local storage. If no theme is found, it defaults to 'standard'. ```javascript const d = new Date(); let id = 'webData'; if (location.href.indexOf('/beta/') >= 0) { id = `@${id}`; } let suffix = ''; if (location.href.indexOf('watch') >= 0) { suffix = '-watch'; document.getElementById('manifest')?.setAttribute('href', 'packages/nightscout_reporter/assets/manifest.watch.json'); } let theme = null; try { const data = JSON.parse(window.localStorage[id]); theme = data['w2']; } catch (ex) { } if (theme == null || theme === '') { theme = 'standard'; } document.getElementById('owl')?.setAttribute('src', 'packages/nightscout_reporter/assets/themes/' + theme + '/owl' + suffix + '.png'); document.getElementById('themestyle')?.setAttribute('href', 'packages/nightscout_reporter/assets/themes/' + theme + '/index.css'); document.getElementById('favicon')?.setAttribute('href', 'packages/nightscout_reporter/assets/themes/' + theme + '/favicon' + suffix + '.png'); ``` -------------------------------- ### User and Settings Management (Dart) Source: https://context7.com/zreptil/nightscout-reporter/llms.txt Manages user preferences, Nightscout URLs, and report form parameters. It includes methods to determine the correct Nightscout URL for a given date, construct API URLs, and validate the Nightscout connection. The class supports multiple Nightscout URLs with date ranges for historical data management. ```dart class UserData { Globals g; var name = ''; var birthDate = ''; var listApiUrl = []; // Multiple Nightscout URLs with date ranges dynamic formParams = {}; // Report-specific parameters String diaStartDate = ''; String insulin = ''; bool adjustGluc = false; // Enable glucose calibration double adjustCalc = 5.0; // Calculated HbA1c double adjustLab = 5.0; // Lab HbA1c for calibration // Get the appropriate URL for a specific date UrlData urlDataFor(Date date) { UrlData ret; for (var url in listApiUrl) { if (url.startDate == null || url.startDate.isOnOrBefore(date)) { if (url.endDate == null || url.endDate.isOnOrAfter(date)) ret = url; } } ret ??= listApiUrl.last; return ret; } // Build API URL for a specific date String apiUrl(Date date, String cmd, {String params = '', bool noApi = false}) { if (listApiUrl.isEmpty) return null; var found = urlDataFor(date); return found.fullUrl(cmd, params: params, noApi: noApi); } // Validate Nightscout connection Future get isValid async { if (apiUrl(null, '') == null) return 'URL not configured'; String ret; var check = apiUrl(null, 'status'); await g.request(check).then((String response) { if (response != '

STATUS OK

') ret = 'URL not reachable'; }).catchError((err) { ret = 'Connection failed'; }); return ret; } } // Example: Configure user with multiple Nightscout URLs var user = UserData(globals); user.name = "John Doe"; user.listApiUrl.add(UrlData(globals) ..url = "https://old-nightscout.herokuapp.com" ..token = "api-secret-token" ..startDate = Date(2020, 1, 1) ..endDate = Date(2022, 12, 31)); user.listApiUrl.add(UrlData(globals) ..url = "https://new-nightscout.herokuapp.com" ..token = "new-api-token" ..startDate = Date(2023, 1, 1) ..endDate = null); // Current URL ``` -------------------------------- ### Manage Nightscout Profile Data with Dart Source: https://context7.com/zreptil/nightscout-reporter/llms.txt The `ProfileStoreData` class in Dart manages Nightscout profile configurations, including basal rates, insulin sensitivity, and carb ratios. It parses JSON data and provides methods to calculate total daily basal insulin. Dependencies include `JsonData`, `ProfileEntryData`, and `ProfileTimezone`. ```dart class ProfileStoreData extends JsonData { String name; double dia; var listCarbratio = []; var listSens = []; var listBasal = []; var listTargetLow = []; var listTargetHigh = []; ProfileTimezone timezone; DateTime startDate; double get ieBasalSum => _listSum(listBasal); double _listSum(List list) { var ret = 0.0; for (var entry in list) { ret += (entry.value ?? 0) * (entry.duration ?? 0) / 3600; } return ret; } factory ProfileStoreData.fromJson(String name, Map json, double percentage, int timeshift, DateTime startDate) { var ret = ProfileStoreData(name); ret.dia = JsonData.toDouble(json['dia']); ret.carbsHr = JsonData.toInt(json['carbs_hr']); ret.timezone = ProfileTimezone(JsonData.toText(json['timezone'])); ret.startDate = startDate; for (dynamic entry in json['basal']) { ret.listBasal.add(ProfileEntryData.fromJson(entry, ret.timezone, timeshift, percentage)); } for (dynamic entry in json['carbratio']) { ret.listCarbratio.add(ProfileEntryData.fromJson(entry, ret.timezone, timeshift, percentage, true)); } for (dynamic entry in json['sens']) { ret.listSens.add(ProfileEntryData.fromJson(entry, ret.timezone, timeshift, percentage, true)); } return ret; } } ProfileGlucData profile = reportData.profile(DateTime.now()); print('Current basal: ${profile.basal.value} U/hr'); print('Current ISF: ${profile.sens.value}'); print('Current ICR: ${profile.carbRatio.value}'); ``` -------------------------------- ### Shortcut Data Management for Report Presets in Dart Source: https://context7.com/zreptil/nightscout-reporter/llms.txt Defines a ShortcutData class to save and apply report configurations, including PDF order, date range, and glucose unit preferences. It allows loading current form selections and applying saved configurations. This class depends on the Globals class and uses JSON serialization/deserialization. ```dart class ShortcutData { Globals g; String name; String pdfOrder; String periodData; int glucMGDLIdx; Map forms = {}; ShortcutData(this.g); // Load current form selections into shortcut void loadCurrentForms() { forms = g.currentFormsAsMap; pdfOrder = g._pdfOrder; } // Apply shortcut configuration void apply() { g.period = DatepickerPeriod(src: periodData); for (var cfg in g.listConfig) { cfg.checked = forms.keys.contains(cfg.form.dataId); if (cfg.checked) { cfg.fillFromJson(forms[cfg.form.dataId]); } } g.glucMGDLIdx = glucMGDLIdx; g.sortConfigs(); } factory ShortcutData.fromJson(Globals g, dynamic json) { var ret = ShortcutData(g); ret.name = json['n']; ret.periodData = json['p']; ret.forms = json['f']; ret.pdfOrder = json['o']; ret.glucMGDLIdx = JsonData.toInt(json['u'], g.glucMGDLIdx); return ret; } // Placeholder for formData getter String get formData => '{}'; String get asJsonString { return '{"n":"$name","p":"$periodData","o":"$pdfOrder","f":$formData,"u":$glucMGDLIdx}'; } } // Dummy classes for compilation abstract class Globals { dynamic period; List listConfig; int glucMGDLIdx; Map get currentFormsAsMap; String get _pdfOrder; void sortConfigs(); } class DatepickerPeriod { DatepickerPeriod({String src}); } class JsonData { static int toInt(dynamic value, int defaultValue) { return defaultValue; } } // Dummy classes for ShortcutData properties class FormConfig { bool checked; String dataId; void fillFromJson(dynamic data) {} } class Form { String dataId; } ``` -------------------------------- ### Parse Nightscout Glucose Readings with EntryData Class (Dart) Source: https://context7.com/zreptil/nightscout-reporter/llms.txt The EntryData class models continuous glucose monitor readings from Nightscout. It includes fields for raw and sensor glucose values, timestamps, device information, and trend direction. The class provides a factory constructor to parse JSON data and a getter to retrieve the adjusted glucose value, handling potential gaps in readings. ```dart class EntryData extends JsonData { String id; DateTime time; String device; String direction; // Trend direction (e.g., "Flat", "FortyFiveUp") double rawbg; // Raw glucose value double sgv; // Sensor glucose value double mbg; // Meter blood glucose (finger stick) String type; // 'sgv' for CGM, 'mbg' for blood glucose bool isGap = false; // Get the glucose value with adjustment factor applied double get gluc { return isGap ? -1 : Globals.adjustFactor * (type == 'sgv' ? sgv : rawbg) ?? 0; } // Parse from Nightscout JSON response factory EntryData.fromJson(Map json) { var ret = EntryData(); ret.id = json['_id']; ret.time = JsonData.toDate(json['date']); ret.device = json['device']; ret.direction = json['direction']; ret.rawbg = JsonData.toDouble(json['rawbg']); ret.type = json['type']; ret.sgv = JsonData.toDouble(json['sgv']); ret.mbg = JsonData.toDouble(json['mbg']); // Mark invalid readings as gaps if (ret.sgv < 20 || ret.sgv > 1000) { ret.sgv = 0; ret.isGap = true; } return ret; } } // Usage example var entriesJson = await requestJson(user.apiUrl(null, 'entries.json', params: 'count=288')); for (var json in entriesJson) { var entry = EntryData.fromJson(json); if (!entry.isGlucInvalid) { print('${entry.time}: ${entry.gluc} mg/dL, direction: ${entry.direction}'); } } ``` -------------------------------- ### Abstract PDF Report Generator (Dart) Source: https://context7.com/zreptil/nightscout-reporter/llms.txt Defines the abstract base class for all PDF report generators. It includes common properties like report ID, title, data requirements, and parameters. It also provides utility methods for calculations (HbA1c), color definitions, and creating table cells. The `getPages` method is abstract and must be implemented by subclasses. ```dart abstract class BasePrint { Globals g = Globals(); String baseId; // Unique identifier for the report String title; // Display title DataNeeded needed; // Specifies what data the report needs List params = []; // Configurable parameters // Calculate HbA1c estimate from average glucose String hba1c(double avgGluc) => avgGluc == null ? '' : g.fmtNumber((avgGluc + 46.7) / 28.7, 1); // Color definitions for charts dynamic colors = { 'colLow': '#ff6666', 'colNorm': '#00cc00', 'colHigh': '#cccc00', 'colBasalProfile': '#0097a7', 'colBolus': '#0060c0', 'colCarbs': '#ffa050', }; // Abstract method to generate PDF content Future> getPages(ReportData data); // Helper to create table cells dynamic cell(double x, double y, double w, double h, String text, {String color, String align, double fontSize}) { return { 'absolutePosition': {'x': x, 'y': y}, 'text': text, 'fontSize': fontSize ?? 10, 'color': color ?? '#000000', 'alignment': align ?? 'left' }; } } // Available report types: // - PrintAnalysis: Overall statistics and analysis // - PrintBasalrate: Basal rate visualization // - PrintCGP: Comprehensive Glucose Pentagon // - PrintDailyAnalysis: Daily detailed analysis // - PrintDailyGluc: Daily glucose values // - PrintDailyGraphic: Daily glucose graphs // - PrintDailyHours: Hourly statistics // - PrintDailyLog: Daily event log // - PrintDailyProfile: Daily profile visualization // - PrintDailyStatistics: Daily statistics table // - PrintGlucDistribution: Glucose distribution chart // - PrintPercentile: Percentile analysis // - PrintProfile: Profile settings display // - PrintWeeklyGraphic: Weekly glucose overview ``` -------------------------------- ### Glucose Unit Conversion and Formatting in Dart Source: https://context7.com/zreptil/nightscout-reporter/llms.txt Handles automatic conversion between mg/dL and mmol/L glucose units. It includes methods for converting glucose values and formatting numbers with localized decimal separators. This class extends a Settings class and relies on a 'language' property for localization. ```dart import 'package:intl/intl.dart'; // Assuming Globals extends Settings and has necessary properties like glucMGDL, language, etc. class Globals extends Settings { // Conversion factor: 1 mmol/L = 18.02 mg/dL double get glucFactor => glucMGDL ? 1 : 18.02; double get glucPrecision => glucMGDL ? 0 : 2; // Assume glucMGDLIdx is a property that determines the unit (e.g., 0 for mg/dL, 1 for mmol/L) bool get glucMGDL => glucMGDLIdx == 0; int glucMGDLIdx = 0; // Default to mg/dL // Assume language and currentFormsAsMap, _pdfOrder properties exist var language = Locale('en', ''); // Placeholder for language object Map get currentFormsAsMap => {}; // Placeholder String get _pdfOrder => ''; // Placeholder // Convert glucose value based on current unit setting String glucFromData(var gluc, [double precision]) { if (gluc is String) gluc = double.tryParse(gluc) ?? 0; if (!(gluc is num) || gluc == 0) return ''; if (!glucMGDL) return fmtNumber(gluc / 18.02, precision ?? 1); return fmtNumber(gluc, precision ?? 0); } // Format number with localized decimal separator String fmtNumber(num value, [num decimals = 0, int fillfront0 = 0, String nullText = 'null', bool stripTrailingZero = false]) { if (value == null) return nullText; var fmt = '#,##0'; if (decimals > 0) { fmt = '${fmt}.'.padRight(decimals + 6, '0'); } var nf = NumberFormat(fmt, language.code); return nf.format(value); } // Placeholder for sortConfigs method void sortConfigs() {} // Placeholder for listConfig property List get listConfig => []; } // Placeholder for Settings class abstract class Settings {} // Placeholder for DatepickerPeriod class class DatepickerPeriod { DatepickerPeriod({String src}); } // Placeholder for JsonData class class JsonData { static int toInt(dynamic value, int defaultValue) { return defaultValue; } } // Usage example var g = Globals(); var gluc = 180; // Value in mg/dL print('mg/dL: ${g.glucFromData(gluc)}'); // Expected: "180" g.glucMGDLIdx = 1; // Switch to mmol/L print('mmol/L: ${g.glucFromData(gluc)}'); // Expected: "10.0" ``` -------------------------------- ### Analyze Daily Glucose and Treatments with Dart Source: https://context7.com/zreptil/nightscout-reporter/llms.txt The `DayData` class in Dart aggregates glucose readings and treatments for a single day, enabling statistical analysis. It calculates metrics such as average glucose, standard deviation, time in range, and total bolus insulin. It also includes a method to compute Insulin on Board (IOB) at a specific time. ```dart class DayData { Date date; ProfileGlucData basalData; int lowCount = 0; int normCount = 0; int highCount = 0; int entryCountValid = 0; double carbs = 0; double min, max, mid; double varianz = 0.0; var entries = []; List treatments = []; double get avgGluc { var ret = 0.0; var count = 0; for (var entry in entries) { if (!entry.isGlucInvalid) { ret += entry.gluc; count++; } } return count > 0 ? ret / count : 0.0; } double stdAbw(bool isMGDL) { var ret = math.sqrt(varianz); if (!isMGDL) ret = ret / 18.02; return ret; } double normPrz(Globals g) => entryCountValid == 0 ? 0 : normCount / entryCountValid * 100; double get ieBolusSum { var ret = 0.0; for (var entry in treatments) { ret += (entry.bolusInsulin ?? 0); } return ret; } CalcIOBData iob(ReportData data, DateTime time, DayData yesterday) { var totalIOB = 0.0; var profile = data.profile(time); for (var t in treatments) { if (t.createdAt.millisecondsSinceEpoch > time.millisecondsSinceEpoch) continue; var tIOB = t.calcIOB(profile, time); if (tIOB?.iob != null) totalIOB += tIOB.iob; } return CalcIOBData(totalIOB, 0.0, null); } } ``` -------------------------------- ### Conditional UI Messaging (Vue.js) Source: https://github.com/zreptil/nightscout-reporter/blob/master/lib/src/controls/signin/signin_component.html This snippet demonstrates conditional rendering of messages in a Vue.js template. It uses ternary operators to display different text based on the 'isBusy', 'isAuthorized' states, and associated message variables. ```html {{isBusy ? msgBusy : isAuthorized ? msgConnected : msgDisconnected}} {{isBusy ? msgBusy : isAuthorized ? msgMenuConnected : msgMenuNotConnected}} ``` -------------------------------- ### Construct Nightscout API URL with UrlData Class (Dart) Source: https://context7.com/zreptil/nightscout-reporter/llms.txt The UrlData class is responsible for constructing the full API URL for Nightscout instances. It handles base URL, optional authentication tokens, and command parameters. This class is essential for directing API requests to the correct Nightscout endpoint. ```dart class UrlData { String url; String token; Date startDate; Date endDate; String fullUrl(String cmd, {String params = '', bool noApi = false}) { var ret = url; if (!ret.endsWith('/')) ret = '$ret/'; if (!noApi) { if (!ret.endsWith('/api/v1/')) ret = '${ret}api/v1/'; } ret = '${ret}$cmd'; if (token != null && token.isNotEmpty) { ret = '${ret}?token=${token}&'; } else { ret = '${ret}?'; } if (params != null && params.isNotEmpty) { ret = '${ret}$params'; } return ret; } } // Example: Fetching glucose entries var url = user.apiUrl(null, 'entries.json', params: 'count=2'); // Produces: https://my-nightscout.herokuapp.com/api/v1/entries.json?token=mytoken&count=2 ``` -------------------------------- ### Parse Diabetes Treatment Data with TreatmentData Class (Dart) Source: https://context7.com/zreptil/nightscout-reporter/llms.txt The TreatmentData class represents various diabetes treatments such as boluses, carbohydrate intake, temporary basals, and care events. It includes fields for event type, duration, timestamps, entered by, carbs, insulin, and notes. The class provides convenience getters for common event types and a method to calculate Insulin on Board (IOB) based on treatment details and profile data. ```dart class TreatmentData extends JsonData { String id; String eventType; // 'Meal Bolus', 'Temp Basal', 'Site Change', etc. int duration; DateTime createdAt; String enteredBy; // Source application (e.g., 'AndroidAPS', 'xdrip') double _carbs; double insulin; double microbolus; bool isSMB; BoluscalcData boluscalc; String notes; // Convenience getters for event types bool get isSiteChange => eventType.toLowerCase() == 'site change'; bool get isSensorChange => eventType.toLowerCase() == 'sensor change'; bool get isTempBasal => eventType.toLowerCase() == 'temp basal'; bool get isMealBolus => eventType.toLowerCase() == 'meal bolus'; bool get isBolusWizard => eventType.toLowerCase() == 'bolus wizard'; // Calculate IOB (Insulin on Board) at a given time CalcIOBData calcIOB(ProfileGlucData profile, DateTime time) { var dia = profile.store?.dia ?? 3.0; var scaleFactor = 3.0 / dia; var peak = 75.0; var ret = CalcIOBData(0.0, 0.0, this); if (insulin != null) { var bolusTime = createdAt.millisecondsSinceEpoch; var minAgo = scaleFactor * (time.millisecondsSinceEpoch - bolusTime) / 1000 / 60; if (minAgo < peak) { var x1 = minAgo / 5 + 1; ret.iob = insulin * (1 - 0.001852 * x1 * x1 + 0.001852 * x1); } else if (minAgo < 180) { var x2 = (minAgo - peak) / 5; ret.iob = insulin * (0.001323 * x2 * x2 - 0.054233 * x2 + 0.55556); } } return ret; } factory TreatmentData.fromJson(Globals g, Map json) { var ret = TreatmentData(); ret.id = JsonData.toText(json['_id']); ret.eventType = JsonData.toText(json['eventType']); ret.duration = JsonData.toInt(json['duration']) * 60; ret.createdAt = JsonData.toDate(json['created_at']); ret.enteredBy = JsonData.toText(json['enteredBy']); ret._carbs = JsonData.toDouble(json['carbs']); ret.insulin = JsonData.toDouble(json['insulin']); ret.isSMB = JsonData.toBool(json['isSMB']); ret.notes = JsonData.toText(json['notes']); return ret; } } ``` -------------------------------- ### Request JSON Data from Nightscout API (Dart) Source: https://context7.com/zreptil/nightscout-reporter/llms.txt The requestJson function facilitates making HTTP requests to the Nightscout API and parsing the JSON responses. It supports different HTTP methods and handles potential errors. This function is crucial for retrieving data from Nightscout. ```dart // Request JSON data from Nightscout API Future requestJson(String url, {String method = 'get', Map headers, body, bool showError = true}) async { dynamic ret = await request(url, method: method, headers: headers, body: body, showError: showError) .then((String response) { if (response == null) return null; response = response.trim(); if (response.startsWith('[') && response.endsWith(']')) { return convert.json.decode(response); } if (response.startsWith('{') && response.endsWith('}')) { return convert.json.decode(response); } return null; }); return ret; } // Example: Fetching current glucose and status var statusUrl = user.apiUrl(null, 'status.json'); dynamic content = await requestJson(statusUrl); if (content != null) { var status = StatusData.fromJson(content); // Access status.settings.units, status.settings.bgTargetBottom, etc. } // Fetch latest glucose entries var entriesUrl = user.apiUrl(null, 'entries.json', params: 'count=10'); List src = await requestJson(entriesUrl); for (var entry in src) { var entryData = EntryData.fromJson(entry); print('Glucose: ${entryData.gluc} at ${entryData.time}'); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.