From ce75fd0f34ba5cb76badf8b219fcdb1d571ffe5f Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Wed, 10 Dec 2025 21:17:49 +0100 Subject: [PATCH] add more instructions, clarify mail support --- CHANGELOG.md | 2 +- INSTRUCTIONS_IOS.md | 13 +-- INSTRUCTIONS_MYWHOOSH_LINK.md | 28 ++++++ INSTRUCTIONS_REMOTE_CONTROL.md | 13 +++ INSTRUCTIONS_ROUVY.md | 0 INSTRUCTIONS_ZWIFT.md | 0 TROUBLESHOOTING.md | 36 ++------ lib/i10n/intl_de.arb | 3 + lib/i10n/intl_en.arb | 4 +- lib/i10n/intl_fr.arb | 5 +- lib/pages/markdown.dart | 95 +++++++++---------- lib/widgets/apps/mywhoosh_link_tile.dart | 2 +- lib/widgets/apps/zwift_mdns_tile.dart | 1 + lib/widgets/apps/zwift_tile.dart | 1 + lib/widgets/menu.dart | 111 +++++++++++++++++++---- lib/widgets/pair_widget.dart | 1 + lib/widgets/ui/connection_method.dart | 13 ++- pubspec.yaml | 7 +- 18 files changed, 221 insertions(+), 114 deletions(-) create mode 100644 INSTRUCTIONS_MYWHOOSH_LINK.md create mode 100644 INSTRUCTIONS_REMOTE_CONTROL.md create mode 100644 INSTRUCTIONS_ROUVY.md create mode 100644 INSTRUCTIONS_ZWIFT.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ec5d50..d67a919 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 4.0.1 (unreleased) +### 4.1.0 (unreleased) **Features**: - control your trainer manually without requiring a controller - just like a Companion app diff --git a/INSTRUCTIONS_IOS.md b/INSTRUCTIONS_IOS.md index c245b2b..0d2c00c 100644 --- a/INSTRUCTIONS_IOS.md +++ b/INSTRUCTIONS_IOS.md @@ -1,12 +1 @@ -**Instructions for using the MyWhoosh "Link" connection method** -1) launch MyWhoosh on the device of your choice -2) launch MyWhoosh Link, check if the "Link" connection works -3) close MyWhoosh Link -4) open BikeControl, follow on screen instructions - -Once you've confirmed the connection in BikeControl you won't have to repeat step 2 and 3 again in the future. This is just to make sure the connection works in general. - -And here's a video with a few explanations: - -[![BikeControl Instruction for iOS](https://img.youtube.com/vi/p8sgQhuufeI/0.jpg)](https://www.youtube.com/watch?v=p8sgQhuufeI) -[https://www.youtube.com/watch?v=p8sgQhuufeI](https://www.youtube.com/watch?v=p8sgQhuufeI) +Moved to [INSTRUCTIONS_MYWHOOSH_LINK.md](INSTRUCTIONS_MYWHOOSH_LINK.md) diff --git a/INSTRUCTIONS_MYWHOOSH_LINK.md b/INSTRUCTIONS_MYWHOOSH_LINK.md new file mode 100644 index 0000000..8288d9f --- /dev/null +++ b/INSTRUCTIONS_MYWHOOSH_LINK.md @@ -0,0 +1,28 @@ +## Instructions for using the MyWhoosh "Link" connection method +* +1) launch MyWhoosh on the device of your choice +2) launch MyWhoosh Link, check if the "Link" connection works +3) close MyWhoosh Link +4) open BikeControl, follow on screen instructions + +Once you've confirmed the connection in BikeControl you won't have to repeat step 2 and 3 again in the future. This is just to make sure the connection works in general. + +And here's a video with a few explanations: + +[![BikeControl Instruction for iOS](https://img.youtube.com/vi/p8sgQhuufeI/0.jpg)](https://www.youtube.com/watch?v=p8sgQhuufeI) +[https://www.youtube.com/watch?v=p8sgQhuufeI](https://www.youtube.com/watch?v=p8sgQhuufeI) + + +## MyWhoosh "Link" method never connects +* +The same network restrictions apply for BikeControl as it applies to MyWhoosh Link app. Please verify with the MyWhoosh Link app if connection is possible at all. +Here are some instructions that can help: + +[https://mywhoosh.com/troubleshoot/](https://mywhoosh.com/troubleshoot/) +[https://www.facebook.com/groups/mywhoosh/posts/1323791068858873/](https://www.facebook.com/groups/mywhoosh/posts/1323791068858873/) + +In essence: +- your two devices (phone, tablet) need to be on the same WiFi network +- on iOS you have to turn off "Private Wi-Fi Address" in the WiFi settings +- Limit IP Address Tracking may need to be disabled +- mesh networks may not work diff --git a/INSTRUCTIONS_REMOTE_CONTROL.md b/INSTRUCTIONS_REMOTE_CONTROL.md new file mode 100644 index 0000000..2e1db96 --- /dev/null +++ b/INSTRUCTIONS_REMOTE_CONTROL.md @@ -0,0 +1,13 @@ +## Remote control is not working - nothing happens +* +- Try to unpair it from your phone / computer Bluetooth settings, then re-pair it. +- Try restarting the pairing process in BikeControl +- try restarting Bluetooth on your phone and on the device you want to control +- If your other device is an iOS device, go to Settings > Accessibility > Touch > AssistiveTouch > Pointer Devices > Devices and pair your device. Make sure AssistiveTouch is enabled. +- it is very important that both devices (e.g. iPhone and iPad) receive the "pairing dialog" after initial connection. If you miss it, unpair and try again. It may take a few seconds for the dialog to appear. Afterwards you may need to click on "Reconnect" in BikeControl / restart BikeControl. + +## Remote control only clicks on a single coordinate on my iPad +* +iOS seems to be buggy here - try this in the iOS settings: +AssistiveTouch settings > Pointer Devices > Devices > Connected Devices > iPhone (or BikeControl iOS) > Button 1 +switch the setting to None, then back to Single-Tap and it should work again diff --git a/INSTRUCTIONS_ROUVY.md b/INSTRUCTIONS_ROUVY.md new file mode 100644 index 0000000..e69de29 diff --git a/INSTRUCTIONS_ZWIFT.md b/INSTRUCTIONS_ZWIFT.md new file mode 100644 index 0000000..e69de29 diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 7094043..6479cd8 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -1,11 +1,14 @@ ## Click / Ride device cannot be found +* You may need to update the firmware in Zwift Companion app. ## Click / Ride device does not send any data +* You may need to update the firmware in Zwift Companion app. ## My Click v2 disconnects after a minute -Check [this](https://github.com/OpenBikeControl/bikecontrol/issues/68) discussion. +* +Check [this](https://github.com/jonasbark/swiftcontrol/issues/68) discussion. To make your Click V2 work best you should connect it in the Zwift app once each day. If you don't do that BikeControl will need to reconnect every minute. @@ -16,38 +19,15 @@ If you don't do that BikeControl will need to reconnect every minute. 4. Close the Zwift app again and connect again in BikeControl ## Android: Connection works, buttons work but nothing happens in MyWhoosh and similar +* - especially for Redmi and other chinese Android devices please follow the instructions on [https://dontkillmyapp.com/](https://dontkillmyapp.com/): - disable battery optimization for BikeControl - enable auto start of BikeControl - grant accessibility permission for BikeControl -- see [https://github.com/OpenBikeControl/bikecontrol/issues/38](https://github.com/OpenBikeControl/bikecontrol/issues/38) for more details +- see [https://github.com/jonasbark/swiftcontrol/issues/38](https://github.com/OpenBikeControl/bikecontrol/issues/38) for more details -## Remote control is not working - nothing happens -- Try to unpair it from your phone / computer Bluetooth settings, then re-pair it. -- Try restarting the pairing process in BikeControl -- try restarting Bluetooth on your phone and on the device you want to control -- If your other device is an iOS device, go to Settings > Accessibility > Touch > AssistiveTouch > Pointer Devices > Devices and pair your device. Make sure AssistiveTouch is enabled. -- it is very important that both devices (e.g. iPhone and iPad) receive the "pairing dialog" after initial connection. If you miss it, unpair and try again. It may take a few seconds for the dialog to appear. Afterwards you may need to click on "Reconnect" in BikeControl / restart BikeControl. - -## Remote control only clicks on a single coordinate on my iPad -iOS seems to be buggy here - try this in the iOS settings: -AssistiveTouch settings > Pointer Devices > Devices > Connected Devices > iPhone (or BikeControl iOS) > Button 1 -switch the setting to None, then back to Single-Tap and it should work again - -## BikeControl crashes on Windows when searching for the device +## BikeControl crashes on Windows when searching for the device +* You're probably running into [this](https://github.com/OpenBikeControl/bikecontrol/issues/70) issue. Disconnect your controller device (e.g. Zwift Play) from Windows Bluetooth settings. -## MyWhoosh "Link" method never connects -The same network restrictions apply for BikeControl as it applies to MyWhoosh Link app. Please verify with the MyWhoosh Link app if connection is possible at all. -Here are some instructions that can help: - -[https://mywhoosh.com/troubleshoot/](https://mywhoosh.com/troubleshoot/) -[https://www.facebook.com/groups/mywhoosh/posts/1323791068858873/](https://www.facebook.com/groups/mywhoosh/posts/1323791068858873/) -[INSTRUCTIONS_IOS.md](INSTRUCTIONS_IOS.md) - -In essence: -- your two devices (phone, tablet) need to be on the same WiFi network -- on iOS you have to turn off "Private Wi-Fi Address" in the WiFi settings -- Limit IP Address Tracking may need to be disabled -- mesh networks may not work diff --git a/lib/i10n/intl_de.arb b/lib/i10n/intl_de.arb index de41b85..bbcea47 100644 --- a/lib/i10n/intl_de.arb +++ b/lib/i10n/intl_de.arb @@ -210,6 +210,7 @@ "ignoredDevices": "Ignorierte Geräte", "importAction": "Import", "importProfile": "Profil importieren", + "instructions": "Anleitung", "jsonData": "JSON-Daten", "keyboardAccess": "Tastaturzugriff", "latestVersion": "aktuell: {version}", @@ -245,6 +246,7 @@ "logsHaveBeenCopiedToClipboard": "Die Protokolle wurden in die Zwischenablage kopiert.", "longPress": "langes\nDrücken", "longPressMode": "Modus „Langes Drücken“ (statt Wiederholen)", + "mailSupportExplanation": "Die individuelle Unterstützung per E-Mail ist für mich sehr aufwendig.\n\nBitte nutze daher Reddit, Facebook oder GitHub für Fragen und Probleme, damit die gesamte Community davon profitieren kann.", "manageIgnoredDevices": "Ignorierte Geräte verwalten", "manageProfile": "Profil verwalten", "mediaKeyDetectionTooltip": "Aktiviere diese Option, damit BikeControl Bluetooth-Fernbedienungen erkennt. \nDazu muss BikeControl als Mediaplayer fungieren.", @@ -260,6 +262,7 @@ "myWhooshDirectConnection": " z. B. mit MyWhoosh „Link”.", "myWhooshLinkConnected": "MyWhoosh „Link“ verbunden", "myWhooshLinkDescriptionLocal": "Verbinde dich direkt mit MyWhoosh über die „Link”-Methode. Unterstützte Aktionen sind unter anderem Schalten, Emotes und Richtungswechsel. Die MyWhoosh Link-Begleit-App darf dabei NICHT gleichzeitig laufen.", + "myWhooshLinkDescriptionRemote": "Du kannst dich über das Netzwerk mit MyWhoosh verbinden, indem du die „Link”-Verbindung nutzt. Die MyWhoosh Link-Begleit-App darf dabei NICHT gleichzeitig laufen.", "nameChangeNotice": "SwiftControl heißt jetzt BikeControl! Es ist Teil des OpenBikeControl-Projekts, das sich für offene Standards bei intelligenten Fahrradtrainern einsetzt und erschwingliche Hardware-Controller entwickelt!", "needHelpClickHelp": "Hilfe benötigt? Klicke auf", "needHelpDontHesitate": "den Button oben und zögere nicht, uns zu kontaktieren.", diff --git a/lib/i10n/intl_en.arb b/lib/i10n/intl_en.arb index 76ebbc8..5462bc8 100644 --- a/lib/i10n/intl_en.arb +++ b/lib/i10n/intl_en.arb @@ -454,5 +454,7 @@ "noConnectionMethodSelected": "No Connection Method selected", "noControllerConnected": "None connected", "notConnected": "Not connected", - "noTrainerSelected": "No Trainer selected" + "noTrainerSelected": "No Trainer selected", + "instructions": "Instructions", + "mailSupportExplanation": "Providing individual support via email is a lot of work for me.\n\nPlease consider using Reddit, Facebook or GitHub for questions and issues so that the whole community can benefit from it." } diff --git a/lib/i10n/intl_fr.arb b/lib/i10n/intl_fr.arb index eea3014..0214a6f 100644 --- a/lib/i10n/intl_fr.arb +++ b/lib/i10n/intl_fr.arb @@ -210,6 +210,7 @@ "ignoredDevices": "Appareils ignorés", "importAction": "Importer", "importProfile": "Profil d'importation", + "instructions": "Mode d'emploi", "jsonData": "Données JSON", "keyboardAccess": "Accès clavier", "latestVersion": "dernier: {version}", @@ -245,6 +246,7 @@ "logsHaveBeenCopiedToClipboard": "Les journaux ont été copiés dans le presse-papiers.", "longPress": "long\nappui", "longPressMode": "Mode appui long (par rapport à la répétition)", + "mailSupportExplanation": "Répondre à tout le monde individuellement par e-mail, ça me prend beaucoup de temps.\n\nSi t'as des questions ou des problèmes, pense à utiliser Reddit, Facebook ou GitHub pour que tout le monde puisse en profiter.", "manageIgnoredDevices": "Gérer les périphériques ignorés", "manageProfile": "Gérer mon profil", "mediaKeyDetectionTooltip": "Activez cette option pour permettre à BikeControl de détecter les télécommandes Bluetooth. Pour ce faire, BikeControl doit fonctionner comme un lecteur multimédia.", @@ -256,10 +258,11 @@ "miuiWarningDescription": "Votre appareil fonctionne sous MIUI, qui est connu pour supprimer de manière agressive les services d'arrière-plan et les services d'accessibilité.", "moreInformation": "Plus d'informations", "mustChooseAllowOrDeny": "Vous devez choisir d'autoriser ou de refuser cette autorisation pour continuer.", - "myWhooshDirectConnectAction": "Action de connexion directe MyWhoosh", + "myWhooshDirectConnectAction": "Action «Link» de MyWhoosh", "myWhooshDirectConnection": " par exemple en utilisant MyWhoosh «Link».", "myWhooshLinkConnected": "MyWhoosh « Link » connecté", "myWhooshLinkDescriptionLocal": "Connecte-toi directement à MyWhoosh avec la méthode « Link ». Tu peux faire des trucs comme changer de vitesse, utiliser des émoticônes, indiquer la direction à prendre, et plein d'autres choses. L'appli MyWhoosh Link ne doit PAS être ouverte en même temps.", + "myWhooshLinkDescriptionRemote": "Ça te permet de te connecter à MyWhoosh via le réseau, en utilisant la connexion « Link ». L'appli MyWhoosh Link ne doit PAS être ouverte en même temps.", "nameChangeNotice": "SwiftControl devient BikeControl ! Ce logiciel fait partie du projet OpenBikeControl, qui promeut les standards ouverts pour les home trainers connectés et conçoit des contrôleurs matériels abordables !", "needHelpClickHelp": "Besoin d'aide ? Cliquez sur le", "needHelpDontHesitate": "bouton en haut et n'hésitez pas à nous contacter.", diff --git a/lib/pages/markdown.dart b/lib/pages/markdown.dart index 05fd7e5..d44d64e 100644 --- a/lib/pages/markdown.dart +++ b/lib/pages/markdown.dart @@ -16,7 +16,7 @@ class MarkdownPage extends StatefulWidget { } class _ChangelogPageState extends State { - Markdown? _markdown; + List<_Group>? _groups; String? _error; @override @@ -28,9 +28,7 @@ class _ChangelogPageState extends State { Future _loadChangelog() async { try { final md = await rootBundle.loadString(widget.assetPath); - setState(() { - _markdown = Markdown.fromString(md); - }); + _parseMarkdown(md); // load latest version final response = await http.get( @@ -39,9 +37,7 @@ class _ChangelogPageState extends State { if (response.statusCode == 200) { final latestMd = response.body; if (latestMd != md) { - setState(() { - _markdown = Markdown.fromString(md); - }); + _parseMarkdown(md); } } } catch (e) { @@ -59,55 +55,37 @@ class _ChangelogPageState extends State { leading: [ BackButton(), ], - title: Text(widget.assetPath.replaceAll('.md', '').toLowerCase().capitalize()), + title: Text( + widget.assetPath + .replaceAll('.md', '') + .split('_') + .joinToString(separator: ' ', transform: (s) => s.toLowerCase().capitalize()), + ), ), ], child: _error != null ? Center(child: Text(_error!)) - : _markdown == null + : _groups == null ? Center(child: CircularProgressIndicator()) : SingleChildScrollView( padding: EdgeInsets.all(16), child: Accordion( - items: _markdown!.blocks.fold([], (acc, block) { - if (block is MD$Heading) { - acc.add( - AccordionItem( - trigger: AccordionTrigger(child: ColoredTitle(text: block.text)), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [], + items: _groups! + .map( + (group) => AccordionItem( + trigger: AccordionTrigger(child: ColoredTitle(text: group.title)), + content: MarkdownWidget( + markdown: group.markdown, + theme: MarkdownThemeData( + textStyle: TextStyle(), + onLinkTap: (title, url) { + launchUrlString(url); + }, + ), ), ), - ); - } else { - ((acc.last as AccordionItem).content as Column).children.add( - switch (block.type) { - _ when block is MD$Paragraph => Text(block.text).small, - _ when block is MD$List => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - for (var item in block.items) ...[ - if (item.children.isEmpty) - fromString(item.text).li - else - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - fromString(item.text), - for (var line in item.children) fromString(line.text).li, - ], - ).li, - ], - ], - ), - _ when block is MD$Spacer => SizedBox(height: 16), - _ => SizedBox.shrink(), - }, - ); - } - return acc; - }), + ) + .toList(), ), ), ); @@ -125,4 +103,29 @@ class _ChangelogPageState extends State { ), ); } + + void _parseMarkdown(String md) { + setState(() { + _groups = md + .split('## ') + .map((section) { + final lines = section.split('\n'); + final title = lines.first.replaceFirst('# ', '').trim(); + final content = lines.skip(1).join('\n').trim(); + return _Group( + title: title, + markdown: Markdown.fromString('## $content'), + ); + }) + .where((group) => group.title.isNotEmpty) + .toList(); + }); + } +} + +class _Group { + final String title; + final Markdown markdown; + + _Group({required this.title, required this.markdown}); } diff --git a/lib/widgets/apps/mywhoosh_link_tile.dart b/lib/widgets/apps/mywhoosh_link_tile.dart index 8da898b..494ee8f 100644 --- a/lib/widgets/apps/mywhoosh_link_tile.dart +++ b/lib/widgets/apps/mywhoosh_link_tile.dart @@ -24,7 +24,7 @@ class _MywhooshLinkTileState extends State { isEnabled: core.settings.getMyWhooshLinkEnabled(), type: ConnectionMethodType.network, title: context.i18n.connectUsingMyWhooshLink, - instructionLink: 'https://github.com/jonasbark/swiftcontrol/blob/main/INSTRUCTIONS_IOS.md', + instructionLink: 'INSTRUCTIONS_MYWHOOSH_LINK.md', description: isConnected ? context.i18n.myWhooshLinkConnected : isStarted diff --git a/lib/widgets/apps/zwift_mdns_tile.dart b/lib/widgets/apps/zwift_mdns_tile.dart index 5e404b2..da86427 100644 --- a/lib/widgets/apps/zwift_mdns_tile.dart +++ b/lib/widgets/apps/zwift_mdns_tile.dart @@ -34,6 +34,7 @@ class _ZwiftTileState extends State { : isConnected ? context.i18n.connected : context.i18n.waitingForConnectionKickrBike(core.settings.getTrainerApp()?.name ?? ''), + instructionLink: 'INSTRUCTIONS_ZWIFT.md', isStarted: isStarted, isConnected: isConnected, onChange: (start) { diff --git a/lib/widgets/apps/zwift_tile.dart b/lib/widgets/apps/zwift_tile.dart index 3481085..325837e 100644 --- a/lib/widgets/apps/zwift_tile.dart +++ b/lib/widgets/apps/zwift_tile.dart @@ -28,6 +28,7 @@ class _ZwiftTileState extends State { return ConnectionMethod( isEnabled: core.settings.getZwiftBleEmulatorEnabled(), type: ConnectionMethodType.bluetooth, + instructionLink: 'INSTRUCTIONS_ZWIFT.md', isStarted: isStarted, isConnected: isConnected, onChange: (value) { diff --git a/lib/widgets/menu.dart b/lib/widgets/menu.dart index 648a250..cfb6638 100644 --- a/lib/widgets/menu.dart +++ b/lib/widgets/menu.dart @@ -7,6 +7,7 @@ import 'package:in_app_review/in_app_review.dart'; import 'package:intl/intl.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:swift_control/bluetooth/devices/zwift/zwift_clickv2.dart'; +import 'package:swift_control/gen/l10n.dart'; import 'package:swift_control/pages/markdown.dart'; import 'package:swift_control/utils/core.dart'; import 'package:swift_control/utils/i18n_extension.dart'; @@ -98,35 +99,111 @@ List buildMenuButtons(BuildContext context, VoidCallback? openLogs) { ); }, ), + MenuDivider(), + MenuLabel(child: Text(context.i18n.getSupport)), MenuButton( - leading: Icon(Icons.bug_report_outlined), - child: Text(context.i18n.provideFeedback), + leading: Icon(Icons.reddit_outlined), + onPressed: (c) { + launchUrlString('https://www.reddit.com/r/BikeControl/'); + }, + child: Text('Reddit'), + ), + MenuButton( + leading: Icon(Icons.facebook_outlined), + onPressed: (c) { + launchUrlString('https://www.facebook.com/groups/1892836898778912'); + }, + child: Text('Facebook'), + ), + MenuButton( + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 3.0), + child: Text('G'), + ), onPressed: (c) { launchUrlString('https://github.com/jonasbark/swiftcontrol/issues'); }, + child: Text('GitHub'), ), - MenuDivider(), - if (!kIsWeb) + if (!kIsWeb) ...[ MenuButton( leading: Icon(Icons.email_outlined), - child: Text(context.i18n.getSupport), + child: Text('Mail'), onPressed: (c) { - final isFromStore = (Platform.isAndroid ? isFromPlayStore == true : Platform.isIOS); - final suffix = isFromStore ? '' : '-sw'; + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Mail Support'), + content: Container( + constraints: BoxConstraints(maxWidth: 400), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16, + children: [ + Text( + AppLocalizations.of(context).mailSupportExplanation, + ), + ...[ + OutlineButton( + leading: Icon(Icons.reddit_outlined), + onPressed: () { + Navigator.pop(context); + launchUrlString('https://www.reddit.com/r/BikeControl/'); + }, + child: const Text('Reddit'), + ), + OutlineButton( + leading: Icon(Icons.facebook_outlined), + onPressed: () { + Navigator.pop(context); + launchUrlString('https://www.facebook.com/groups/1892836898778912'); + }, + child: const Text('Facebook'), + ), + OutlineButton( + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 3.0), + child: Text('G'), + ), + onPressed: () { + Navigator.pop(context); + launchUrlString('https://github.com/jonasbark/swiftcontrol/issues'); + }, + child: const Text('GitHub'), + ), + SecondaryButton( + leading: Icon(Icons.mail_outlined), + onPressed: () { + Navigator.pop(context); - String email = Uri.encodeComponent('jonas$suffix@bikecontrol.app'); - String subject = Uri.encodeComponent( - context.i18n.helpRequested(packageInfoValue?.version ?? ''), + final isFromStore = (Platform.isAndroid + ? isFromPlayStore == true + : Platform.isIOS); + final suffix = isFromStore ? '' : '-sw'; + + String email = Uri.encodeComponent('jonas$suffix@bikecontrol.app'); + String subject = Uri.encodeComponent( + context.i18n.helpRequested(packageInfoValue?.version ?? ''), + ); + String body = Uri.encodeComponent(""" + ${debugText()}"""); + Uri mail = Uri.parse("mailto:$email?subject=$subject&body=$body"); + + launchUrl(mail); + }, + child: const Text('Mail'), + ), + ], + ], + ), + ), + ); + }, ); - String body = Uri.encodeComponent(""" - ${debugText()} - -${context.i18n.attachLogFile(File('${Directory.current.path}/app.logs').path)}"""); - Uri mail = Uri.parse("mailto:$email?subject=$subject&body=$body"); - - launchUrl(mail); }, ), + ], ], ), ); diff --git a/lib/widgets/pair_widget.dart b/lib/widgets/pair_widget.dart index 6295d9c..dcfa843 100644 --- a/lib/widgets/pair_widget.dart +++ b/lib/widgets/pair_widget.dart @@ -30,6 +30,7 @@ class _PairWidgetState extends State { isStarted: isStarted, showTroubleshooting: true, type: ConnectionMethodType.bluetooth, + instructionLink: 'INSTRUCTIONS_REMOTE_CONTROL.md', title: context.i18n.enablePairingProcess, description: context.i18n.pairingDescription, isConnected: isConnected, diff --git a/lib/widgets/ui/connection_method.dart b/lib/widgets/ui/connection_method.dart index efa1267..4355d42 100644 --- a/lib/widgets/ui/connection_method.dart +++ b/lib/widgets/ui/connection_method.dart @@ -1,6 +1,7 @@ import 'package:dartx/dartx.dart'; import 'package:flutter/foundation.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:swift_control/gen/l10n.dart'; import 'package:swift_control/pages/button_edit.dart'; import 'package:swift_control/pages/markdown.dart'; import 'package:swift_control/utils/i18n_extension.dart'; @@ -8,7 +9,6 @@ import 'package:swift_control/utils/requirements/platform.dart'; import 'package:swift_control/widgets/ui/beta_pill.dart'; import 'package:swift_control/widgets/ui/small_progress_indicator.dart'; import 'package:swift_control/widgets/ui/toast.dart'; -import 'package:url_launcher/url_launcher_string.dart'; enum ConnectionMethodType { bluetooth, @@ -154,13 +154,16 @@ class _ConnectionMethodState extends State with WidgetsBinding style: widget.isEnabled && Theme.of(context).brightness == Brightness.light ? ButtonStyle.outline().withBorder(border: Border.all(color: Colors.gray.shade500)) : ButtonStyle.outline(), - leading: Icon(Icons.play_circle_outline_outlined), + leading: Icon(Icons.help_outline), onPressed: () { - launchUrlString(widget.instructionLink!); + Navigator.push( + context, + MaterialPageRoute(builder: (c) => MarkdownPage(assetPath: widget.instructionLink!)), + ); }, - child: Text(context.i18n.videoInstructions), + child: Text(AppLocalizations.of(context).instructions), ), - if (widget.showTroubleshooting) + if (widget.showTroubleshooting && widget.instructionLink == null) Button( style: widget.isEnabled && Theme.of(context).brightness == Brightness.light ? ButtonStyle.outline().withBorder(border: Border.all(color: Colors.gray.shade500)) diff --git a/pubspec.yaml b/pubspec.yaml index f036c71..40e1d3d 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: swift_control description: "BikeControl - Control your virtual riding" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 4.0.0+48 +version: 4.1.0+49 environment: sdk: ^3.9.0 @@ -83,7 +83,10 @@ flutter: assets: - CHANGELOG.md - TROUBLESHOOTING.md - - INSTRUCTIONS_IOS.md + - INSTRUCTIONS_MYWHOOSH_LINK.md + - INSTRUCTIONS_REMOTE_CONTROL.md + - INSTRUCTIONS_ROUVY.md + - INSTRUCTIONS_ZWIFT.md - shorebird.yaml - icon.png