├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── manifest.json
└── index.html
├── assets
├── OpenHaystackIcon.png
└── accessory_icons
│ ├── pets.png
│ ├── work.png
│ ├── place.png
│ ├── redeem.png
│ ├── school.png
│ ├── favorite.png
│ ├── language.png
│ ├── push_pin.png
│ ├── vpn_key.png
│ ├── bug_report.png
│ ├── credit_card.png
│ ├── pedal_bike.png
│ ├── visibility.png
│ ├── directions_car.png
│ ├── business_center.png
│ └── directions_walk.png
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── seemoo_lab_21_22
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── build.gradle
└── settings.gradle
├── lib
├── ffi
│ ├── ffi_web.dart
│ ├── ffi.dart
│ ├── bridge_generated.web.dart
│ ├── bridge_generated.dart
│ └── bridge_generated.io.dart
├── item_management
│ ├── loading_spinner.dart
│ ├── accessory_id_input.dart
│ ├── accessory_name_input.dart
│ ├── accessory_color_input.dart
│ ├── accessory_pk_input.dart
│ ├── accessory_icon_input.dart
│ ├── item_management.dart
│ ├── new_item_action.dart
│ ├── item_import.dart
│ ├── item_creation.dart
│ ├── item_export.dart
│ └── item_file_import.dart
├── placeholder
│ ├── avatar_placeholder.dart
│ └── text_placeholder.dart
├── deployment
│ ├── hyperlink.dart
│ ├── code_block.dart
│ ├── deployment_linux_hci.dart
│ ├── deployment_esp32.dart
│ ├── deployment_nrf51.dart
│ ├── deployment_details.dart
│ └── deployment_email.dart
├── accessory
│ ├── accessory_list_item_placeholder.dart
│ ├── no_accessories.dart
│ ├── accessory_icon.dart
│ ├── accessory_icon_model.dart
│ ├── accessory_color_selector.dart
│ ├── accessory_icon_selector.dart
│ ├── accessory_list_item.dart
│ ├── accessory_dto.dart
│ ├── accessory_registry.dart
│ ├── accessory_detail.dart
│ ├── accessory_list.dart
│ └── accessory_model.dart
├── findMy
│ ├── reports_fetcher.dart
│ ├── models.dart
│ ├── decrypt_reports.dart
│ └── find_my_controller.dart
├── splashscreen.dart
├── history
│ ├── days_selection_slider.dart
│ └── accessory_history.dart
├── dashboard
│ ├── accessory_map_list_vert.dart
│ ├── dashboard_desktop.dart
│ └── dashboard_mobile.dart
├── preferences
│ ├── user_preferences_model.dart
│ └── preferences_page.dart
├── main.dart
├── location
│ └── location_model.dart
└── map
│ └── map.dart
├── .metadata
├── native
├── src
│ ├── lib.rs
│ ├── bridge_generated.web.rs
│ ├── api.rs
│ ├── bridge_generated.io.rs
│ └── bridge_generated.rs
└── Cargo.toml
├── README.md
├── .gitignore
├── test
└── widget_test.dart
├── CITATION.cff
├── analysis_options.yaml
├── .github
└── workflows
│ └── ubuntu.yml
└── pubspec.yaml
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/assets/OpenHaystackIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/OpenHaystackIcon.png
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/assets/accessory_icons/pets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/pets.png
--------------------------------------------------------------------------------
/assets/accessory_icons/work.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/work.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/assets/accessory_icons/place.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/place.png
--------------------------------------------------------------------------------
/assets/accessory_icons/redeem.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/redeem.png
--------------------------------------------------------------------------------
/assets/accessory_icons/school.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/school.png
--------------------------------------------------------------------------------
/assets/accessory_icons/favorite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/favorite.png
--------------------------------------------------------------------------------
/assets/accessory_icons/language.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/language.png
--------------------------------------------------------------------------------
/assets/accessory_icons/push_pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/push_pin.png
--------------------------------------------------------------------------------
/assets/accessory_icons/vpn_key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/vpn_key.png
--------------------------------------------------------------------------------
/assets/accessory_icons/bug_report.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/bug_report.png
--------------------------------------------------------------------------------
/assets/accessory_icons/credit_card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/credit_card.png
--------------------------------------------------------------------------------
/assets/accessory_icons/pedal_bike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/pedal_bike.png
--------------------------------------------------------------------------------
/assets/accessory_icons/visibility.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/visibility.png
--------------------------------------------------------------------------------
/assets/accessory_icons/directions_car.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/directions_car.png
--------------------------------------------------------------------------------
/assets/accessory_icons/business_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/business_center.png
--------------------------------------------------------------------------------
/assets/accessory_icons/directions_walk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/assets/accessory_icons/directions_walk.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangwillian0/openhaystack/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/seemoo_lab_21_22/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package de.seemoo.android.openhaystack
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/lib/ffi/ffi_web.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
3 | import 'bridge_generated.web.dart';
4 |
5 | const _root = 'pkg/native';
6 |
7 | final api = NativeImpl.wasm(
8 | WasmModule.initialize(kind: const Modules.noModules(root: _root)),
9 | );
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Apr 28 22:51:27 BRT 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 18116933e77adc82f80866c928266a5b4f1ed645
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/native/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod bridge_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */
2 | mod api;
3 | pub fn add(left: usize, right: usize) -> usize {
4 | left + right
5 | }
6 |
7 | #[cfg(test)]
8 | mod tests {
9 | use super::*;
10 |
11 | #[test]
12 | fn it_works() {
13 | let result = add(2, 2);
14 | assert_eq!(result, 4);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/native/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "native"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | crate-type = ["staticlib", "cdylib", "rlib"]
8 |
9 | [dependencies]
10 | flutter_rust_bridge = "^1.78.6"
11 | p224 = "^0.13.2"
12 | getrandom = "^0.2.14"
13 | rayon = "1.10.0"
14 | wasm-bindgen = "0.2.92"
15 |
16 | [features]
17 | default = ["p224/ecdh", "getrandom/js"]
18 |
19 | [profile.release]
20 | opt-level = 3
21 | lto = true
22 |
23 | [package.metadata.wasm-pack.profile.release]
24 | wasm-opt = ["-O4"]
25 |
26 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | afterEvaluate { project ->
11 | if (project.hasProperty('android')) {
12 | project.android {
13 | if (namespace == null) {
14 | namespace project.group
15 | }
16 | }
17 | }
18 | }
19 | project.buildDir = "${rootProject.buildDir}/${project.name}"
20 | project.evaluationDependsOn(':app')
21 | }
22 |
23 | tasks.register("clean", Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/lib/item_management/loading_spinner.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class LoadingSpinner extends StatelessWidget {
4 |
5 | /// Displays a centered loading spinner.
6 | const LoadingSpinner({ Key? key }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Row(
11 | mainAxisAlignment: MainAxisAlignment.center,
12 | children: [Padding(
13 | padding: const EdgeInsets.only(top: 20),
14 | child: CircularProgressIndicator(
15 | color: Theme.of(context).primaryColor,
16 | semanticsLabel: 'Loading. Please wait.',
17 | ),
18 | )],
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/placeholder/avatar_placeholder.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AvatarPlaceholder extends StatelessWidget {
4 | final double size;
5 |
6 | /// Displays a placeholder for the actual avatar, occupying the same layout space.
7 | const AvatarPlaceholder({
8 | Key? key,
9 | this.size = 24,
10 | }) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | width: size * 3 / 2,
16 | height: size * 3 / 2,
17 | decoration: const BoxDecoration(
18 | color: Color.fromARGB(255, 200, 200, 200),
19 | shape: BoxShape.circle,
20 | ),
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/ffi/ffi.dart:
--------------------------------------------------------------------------------
1 | // This file initializes the dynamic library and connects it with the stub
2 | // generated by flutter_rust_bridge_codegen.
3 |
4 | import 'dart:ffi';
5 |
6 | import 'bridge_generated.dart';
7 |
8 | // Re-export the bridge so it is only necessary to import this file.
9 | export 'bridge_generated.dart';
10 | import 'dart:io' as io;
11 |
12 | const _root = 'native';
13 |
14 | // On MacOS, the dynamic library is not bundled with the binary,
15 | // but rather directly **linked** against the binary.
16 | final _dylib = io.Platform.isWindows ? '$_root.dll' : 'lib$_root.so';
17 |
18 | final Native api = NativeImpl(io.Platform.isIOS || io.Platform.isMacOS
19 | ? DynamicLibrary.executable()
20 | : DynamicLibrary.open(_dylib));
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }()
9 |
10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
11 |
12 | repositories {
13 | google()
14 | mavenCentral()
15 | gradlePluginPortal()
16 | }
17 | }
18 |
19 | plugins {
20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
21 | id "com.android.application" version "8.2.1" apply false
22 | id "org.jetbrains.kotlin.android" version "1.8.20" apply false
23 | }
24 |
25 | include ":app"
26 |
--------------------------------------------------------------------------------
/lib/deployment/hyperlink.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:url_launcher/url_launcher.dart';
3 |
4 | class Hyperlink extends StatelessWidget {
5 | /// The target url to open.
6 | String target;
7 | /// The display text of the hyperlink. Default is [target].
8 | String _text;
9 |
10 | /// Displays a hyperlink that can be opened by a tap.
11 | Hyperlink({
12 | Key? key,
13 | required this.target,
14 | text,
15 | }) : _text = text ?? target, super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return InkWell(
20 | child: Text(_text,
21 | style: const TextStyle(
22 | color: Colors.blue,
23 | decoration: TextDecoration.underline,
24 | ),
25 | ),
26 | onTap: () {
27 | launch(target);
28 | },
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a fork of [SEEMOO's Openhaystack mobile app](https://github.com/seemoo-lab/openhaystack/tree/main/OpenHaystack)
2 |
3 | # Main improvements over the original project
4 | - Vector map: smoother, faster and prettier map
5 | - Performance improvements: less than 2 seconds to decrypt 2000 history locations (even on your browser!)
6 | - Server endpoint as user preference: bring your how Openhaystack server without recompiling
7 | - Better history visualization: color encoded points
8 | - Web version: try it now at https://find.willian.wang/
9 |
10 | # About OpenHaystack
11 | OpenHaystack is a project that allows location tracking of Bluetooth Low Energy (BLE) devices over Apples Find My Network.
12 |
13 | # About the code
14 | 🚧
15 |
16 | For now, it's possible to build it by reproducing the [Github Actions workflow](https://github.com/wangwillian0/openhaystack/blob/main/.github/workflows/ubuntu.yml)
17 |
18 |
--------------------------------------------------------------------------------
/lib/accessory/accessory_list_item_placeholder.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:openhaystack_mobile/accessory/accessory_list_item.dart';
3 | import 'package:openhaystack_mobile/placeholder/avatar_placeholder.dart';
4 | import 'package:openhaystack_mobile/placeholder/text_placeholder.dart';
5 |
6 | class AccessoryListItemPlaceholder extends StatelessWidget {
7 |
8 | /// A placeholder for an [AccessoryListItem] showing a loading animation.
9 | const AccessoryListItemPlaceholder({
10 | Key? key,
11 | }) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | // Uses a similar layout to the actual accessory list item
16 | return const ListTile(
17 | title: TextPlaceholder(),
18 | subtitle: TextPlaceholder(),
19 | dense: true,
20 | leading: AvatarPlaceholder(),
21 | trailing: TextPlaceholder(width: 60),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/findMy/reports_fetcher.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:http/http.dart' as http;
4 |
5 | class ReportsFetcher {
6 | /// Fetches the location reports corresponding to the given hashed advertisement
7 | /// key.
8 | /// Throws [Exception] if no answer was received.
9 | static Future fetchLocationReports(String hashedAdvertisementKey, String seemooEndpoint) async {
10 | final response = await http.post(Uri.parse(seemooEndpoint),
11 | headers: {
12 | "Content-Type": "application/json",
13 | },
14 | body: jsonEncode({
15 | "ids": [hashedAdvertisementKey],
16 | }));
17 |
18 | if (response.statusCode == 200) {
19 | return await jsonDecode(response.body)["results"];
20 | } else {
21 | throw Exception("Failed to fetch location reports with statusCode:${response.statusCode}\n\n Response:\n${response}");
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 |
36 | # Symbolication related
37 | app.*.symbols
38 |
39 | # Obfuscation related
40 | app.*.map.json
41 |
42 | # Android Studio will place build artifacts here
43 | /android/app/debug
44 | /android/app/profile
45 | /android/app/release
46 |
47 | # FFI
48 | jniLibs
49 |
50 | # Rust
51 | /native/target
52 |
53 | # VSCode
54 | .vscode
55 |
--------------------------------------------------------------------------------
/lib/accessory/no_accessories.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:openhaystack_mobile/item_management/new_item_action.dart';
3 |
4 | class NoAccessoriesPlaceholder extends StatelessWidget {
5 |
6 | /// Displays a message that no accessories are present.
7 | ///
8 | /// Allows the user to quickly add a new accessory.
9 | const NoAccessoriesPlaceholder({ Key? key }) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Center(
14 | child: Column(
15 | mainAxisAlignment: MainAxisAlignment.center,
16 | children: const [
17 | Text(
18 | 'There\'s Nothing Here Yet\nAdd an accessory to get started.',
19 | style: TextStyle(
20 | fontSize: 20,
21 | color: Colors.grey,
22 | ),
23 | textAlign: TextAlign.center,
24 | ),
25 | NewKeyAction(mini: true),
26 | ],
27 | ),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/splashscreen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Splashscreen extends StatelessWidget {
4 |
5 | /// Display a fullscreen splashscreen to cover loading times.
6 | const Splashscreen({ Key? key }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | Size screenSize = MediaQuery.of(context).size;
11 | Orientation orientation = MediaQuery.of(context).orientation;
12 |
13 | var maxScreen = orientation == Orientation.portrait ? screenSize.width : screenSize.height;
14 | var maxSize = maxScreen * 0.4;
15 |
16 | return Scaffold(
17 | body: Center(
18 | child: Container(
19 | constraints: BoxConstraints(maxWidth: maxSize, maxHeight: maxSize),
20 | // TODO: Update app icon accordingly (https://docs.flutter.dev/development/ui/assets-and-images#platform-assets)
21 | child: const Image(
22 | width: 1800,
23 | image: AssetImage('assets/OpenHaystackIcon.png')),
24 | ),
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/item_management/accessory_id_input.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AccessoryIdInput extends StatelessWidget {
4 | ValueChanged changeListener;
5 |
6 | /// Displays an input field with validation for an accessory ID.
7 | AccessoryIdInput({
8 | Key? key,
9 | required this.changeListener,
10 | }) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Padding(
15 | padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
16 | child: TextFormField(
17 | decoration: const InputDecoration(
18 | labelText: 'ID',
19 | ),
20 | validator: (value) {
21 | if (value == null) {
22 | return 'ID must be provided.';
23 | }
24 | int? parsed = int.tryParse(value);
25 | if (parsed == null) {
26 | return 'ID must be an integer value.';
27 | }
28 | return null;
29 | },
30 | onSaved: changeListener,
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "openhaystack_mobile",
3 | "short_name": "openhaystack_mobile",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "OpenHaystack2.0",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/native/src/bridge_generated.web.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 | // Section: wire functions
3 |
4 | #[wasm_bindgen]
5 | pub fn wire_ecdh(port_: MessagePort, public_key_blob: Box<[u8]>, private_key: Box<[u8]>) {
6 | wire_ecdh_impl(port_, public_key_blob, private_key)
7 | }
8 |
9 | // Section: allocate functions
10 |
11 | // Section: related functions
12 |
13 | // Section: impl Wire2Api
14 |
15 | impl Wire2Api> for Box<[u8]> {
16 | fn wire2api(self) -> Vec {
17 | self.into_vec()
18 | }
19 | }
20 | // Section: impl Wire2Api for JsValue
21 |
22 | impl Wire2Api