diff --git a/.gitmodules b/.gitmodules
index 436efc8c1..73fa8ce3d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,3 +6,6 @@
path = flutter
url = https://github.com/flutter/flutter.git
branch = stable
+[submodule "assets/simple-icons"]
+ path = assets/simple-icons
+ url = https://github.com/simple-icons/simple-icons.git
diff --git a/README.md b/README.md
index aec9ce0e7..66319b161 100644
--- a/README.md
+++ b/README.md
@@ -101,6 +101,14 @@ For maintainers, there is [additional documentation](RELEASES.md) on
automatically publishing the main branch to App store, Play store and GitHub
releases.
+## 🙂 Icons
+
+ente Auth supports the icon pack provided by
+[simple-icons](https://github.com/simple-icons/simple-icons).
+
+If you would like to add your own custom icon, please create a pull-request with
+an SVG for your service that matches the contents within `assets/custom-icons`.
+
## 🙋♂️ Support
If you need help, please reach out to support@ente.io, and a human will get in
diff --git a/assets/build/.last_build_id b/assets/build/.last_build_id
new file mode 100644
index 000000000..b45c7b4f4
--- /dev/null
+++ b/assets/build/.last_build_id
@@ -0,0 +1 @@
+f23611a675a8c9bc71eb16e8a1108cf8
\ No newline at end of file
diff --git a/assets/custom-icons/_data/custom-icons.json b/assets/custom-icons/_data/custom-icons.json
new file mode 100644
index 000000000..312f12e75
--- /dev/null
+++ b/assets/custom-icons/_data/custom-icons.json
@@ -0,0 +1,8 @@
+{
+ "icons": [
+ {
+ "title": "ente",
+ "hex": "1DB954"
+ }
+ ]
+}
diff --git a/assets/custom-icons/icons/ente.svg b/assets/custom-icons/icons/ente.svg
new file mode 100644
index 000000000..18861f453
--- /dev/null
+++ b/assets/custom-icons/icons/ente.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/simple-icons b/assets/simple-icons
new file mode 160000
index 000000000..7e1ad4517
--- /dev/null
+++ b/assets/simple-icons
@@ -0,0 +1 @@
+Subproject commit 7e1ad4517598f36ba625741a4dfbc33610d105d8
diff --git a/lib/main.dart b/lib/main.dart
index 91c8549c9..20d6dd9b0 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -17,6 +17,7 @@ import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/ui/tools/app_lock.dart';
import 'package:ente_auth/ui/tools/lock_screen.dart';
+import 'package:ente_auth/ui/utils/icon_utils.dart';
import 'package:ente_auth/utils/crypto_util.dart';
import 'package:flutter/foundation.dart';
import "package:flutter/material.dart";
@@ -85,4 +86,5 @@ Future _init(bool bool, {String? via}) async {
await BillingService.instance.init();
await NotificationService.instance.init();
await UpdateService.instance.init();
+ await IconUtils.instance.init();
}
diff --git a/lib/ui/code_widget.dart b/lib/ui/code_widget.dart
index 85f78b05b..cb82f225f 100644
--- a/lib/ui/code_widget.dart
+++ b/lib/ui/code_widget.dart
@@ -8,6 +8,7 @@ import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart';
import 'package:ente_auth/onboarding/view/view_qr_page.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/ui/code_timer_progress.dart';
+import 'package:ente_auth/ui/utils/icon_utils.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/toast_util.dart';
import 'package:ente_auth/utils/totp_util.dart';
@@ -81,7 +82,7 @@ class _CodeWidgetState extends State {
backgroundColor: Colors.grey.withOpacity(0.1),
borderRadius: const BorderRadius.all(Radius.circular(12.0)),
foregroundColor:
- Theme.of(context).colorScheme.inverseBackgroundColor,
+ Theme.of(context).colorScheme.inverseBackgroundColor,
icon: Icons.qr_code_2_outlined,
label: "QR",
padding: const EdgeInsets.only(left: 4, right: 0),
@@ -90,7 +91,6 @@ class _CodeWidgetState extends State {
const SizedBox(
width: 4,
),
-
SlidableAction(
onPressed: _onEditPressed,
backgroundColor: Colors.grey.withOpacity(0.1),
@@ -171,14 +171,23 @@ class _CodeWidgetState extends State {
),
],
),
- widget.code.hasSynced != null &&
- widget.code.hasSynced!
- ? Container()
- : const Icon(
- Icons.sync_disabled,
- size: 20,
- color: Colors.amber,
- ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ widget.code.hasSynced != null &&
+ widget.code.hasSynced!
+ ? Container()
+ : const Icon(
+ Icons.sync_disabled,
+ size: 20,
+ color: Colors.amber,
+ ),
+ const SizedBox(width: 12),
+ IconUtils.instance.getIcon(
+ safeDecode(widget.code.issuer).trim(),
+ ),
+ ],
+ ),
],
),
),
@@ -231,7 +240,7 @@ class _CodeWidgetState extends State {
style:
Theme.of(context).textTheme.caption,
),
- InkWell(
+ InkWell(
onTap: _onNextHotpTapped,
child: const Icon(
Icons.forward_outlined,
@@ -264,8 +273,13 @@ class _CodeWidgetState extends State {
}
void _onNextHotpTapped() {
- if(widget.code.type == Type.hotp) {
- CodeStore.instance.addCode(widget.code.copyWith(counter: widget.code.counter + 1), shouldSync: true).ignore();
+ if (widget.code.type == Type.hotp) {
+ CodeStore.instance
+ .addCode(
+ widget.code.copyWith(counter: widget.code.counter + 1),
+ shouldSync: true,
+ )
+ .ignore();
}
}
@@ -306,7 +320,6 @@ class _CodeWidgetState extends State {
);
}
-
String _getCurrentOTP() {
try {
return getOTP(widget.code);
diff --git a/lib/ui/utils/icon_utils.dart b/lib/ui/utils/icon_utils.dart
new file mode 100644
index 000000000..61e743f0f
--- /dev/null
+++ b/lib/ui/utils/icon_utils.dart
@@ -0,0 +1,70 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_svg/svg.dart';
+
+class IconUtils {
+ IconUtils._privateConstructor();
+
+ static final IconUtils instance = IconUtils._privateConstructor();
+
+ // Map of icon-title to the color code in HEX
+ final Map _simpleIcons = {};
+ final Map _customIcons = {};
+
+ Future init() async {
+ await _loadJson();
+ }
+
+ Widget getIcon(String provider) {
+ final title = _getProviderTitle(provider);
+ if (_simpleIcons.containsKey(title)) {
+ return _getSVGIcon(
+ "assets/simple-icons/icons/$title.svg",
+ title,
+ _simpleIcons[title]!,
+ );
+ } else if (_customIcons.containsKey(title)) {
+ return _getSVGIcon(
+ "assets/custom-icons/icons/$title.svg",
+ title,
+ _customIcons[title]!,
+ );
+ } else {
+ return Text(title);
+ }
+ }
+
+ Widget _getSVGIcon(String path, String title, String color) {
+ return SvgPicture.asset(
+ path,
+ width: 24,
+ semanticsLabel: title,
+ colorFilter: ColorFilter.mode(
+ Color(int.parse("0xFF" + color)),
+ BlendMode.srcIn,
+ ),
+ );
+ }
+
+ Future _loadJson() async {
+ final simpleIconData = await rootBundle
+ .loadString('assets/simple-icons/_data/simple-icons.json');
+ final simpleIcons = json.decode(simpleIconData);
+ for (final icon in simpleIcons["icons"]) {
+ _simpleIcons[icon["title"].toString().toLowerCase()] = icon["hex"];
+ }
+ final customIconData = await rootBundle
+ .loadString('assets/custom-icons/_data/custom-icons.json');
+ final customIcons = json.decode(customIconData);
+ for (final icon in customIcons["icons"]) {
+ _customIcons[icon["title"].toString().toLowerCase()] = icon["hex"];
+ }
+ }
+
+ String _getProviderTitle(String provider) {
+ return provider.split(".")[0].toLowerCase();
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index 381bb81b6..b4679d3c8 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -589,6 +589,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.2.0"
+ flutter_svg:
+ dependency: "direct main"
+ description:
+ name: flutter_svg
+ sha256: f991fdb1533c3caeee0cdc14b04f50f0c3916f0dbcbc05237ccbe4e3c6b93f3f
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.5"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -1556,6 +1564,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.7"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: ea8d3fc7b2e0f35de38a7465063ecfcf03d8217f7962aa2a6717132cb5d43a79
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.5"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: a5eaa5d19e123ad4f61c3718ca1ed921c4e6254238d9145f82aa214955d9aced
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.5"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: "15edc42f7eaa478ce854eaf1fbb9062a899c0e4e56e775dd73b7f4709c97c4ca"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.5"
vector_math:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index acb801ce7..7d97eeb70 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -44,6 +44,7 @@ dependencies:
git:
url: https://github.com/ente-io/flutter_sodium.git
flutter_speed_dial: ^6.2.0
+ flutter_svg: ^2.0.5
fluttertoast: ^8.1.1
google_nav_bar: ^5.0.5 #supported
http: ^0.13.4
@@ -92,6 +93,10 @@ flutter:
# https://docs:flutter:dev/development/ui/assets-and-images:
assets:
- assets/
+ - assets/simple-icons/icons/
+ - assets/simple-icons/_data/
+ - assets/custom-icons/icons/
+ - assets/custom-icons/_data/
fonts:
- family: Inter
diff --git a/screenshots/screenshots.png b/screenshots/screenshots.png
index 3fc33eefd..c587e5a04 100644
Binary files a/screenshots/screenshots.png and b/screenshots/screenshots.png differ