diff --git a/flutter/assets/auth-apple.svg b/flutter/assets/auth-apple.svg new file mode 100644 index 000000000..a3c2e871d --- /dev/null +++ b/flutter/assets/auth-apple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/assets/auth-azure.svg b/flutter/assets/auth-azure.svg new file mode 100644 index 000000000..0482b22e6 --- /dev/null +++ b/flutter/assets/auth-azure.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/assets/auth-default.svg b/flutter/assets/auth-default.svg new file mode 100644 index 000000000..905c9ca9b --- /dev/null +++ b/flutter/assets/auth-default.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/flutter/assets/auth-facebook.svg b/flutter/assets/auth-facebook.svg new file mode 100644 index 000000000..d921a6716 --- /dev/null +++ b/flutter/assets/auth-facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/assets/GitHub.svg b/flutter/assets/auth-github.svg similarity index 100% rename from flutter/assets/GitHub.svg rename to flutter/assets/auth-github.svg diff --git a/flutter/assets/Google.svg b/flutter/assets/auth-google.svg similarity index 100% rename from flutter/assets/Google.svg rename to flutter/assets/auth-google.svg diff --git a/flutter/assets/Okta.svg b/flutter/assets/auth-okta.svg similarity index 100% rename from flutter/assets/Okta.svg rename to flutter/assets/auth-okta.svg diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index e96f02772..71fbfcdd9 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -2314,3 +2314,10 @@ Widget unreadTopRightBuilder(RxInt? count, {Widget? icon}) { ], ); } + +String toCapitalized(String s) { + if (s.isEmpty) { + return s; + } + return s.substring(0, 1).toUpperCase() + s.substring(1); +} diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index 17cc7090c..1eecdc2d5 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -13,13 +13,13 @@ import '../../common.dart'; import './dialog.dart'; class _IconOP extends StatelessWidget { - final String icon; - final double iconWidth; + final String op; + final String? icon; final EdgeInsets margin; const _IconOP( {Key? key, + required this.op, required this.icon, - required this.iconWidth, this.margin = const EdgeInsets.symmetric(horizontal: 4.0)}) : super(key: key); @@ -27,10 +27,15 @@ class _IconOP extends StatelessWidget { Widget build(BuildContext context) { return Container( margin: margin, - child: SvgPicture.asset( - 'assets/$icon.svg', - width: iconWidth, - ), + child: icon == null + ? SvgPicture.asset( + 'assets/auth-${op.toLowerCase()}.svg', + width: 20, + ) + : SvgPicture.string( + icon!, + width: 20, + ), ); } } @@ -38,7 +43,7 @@ class _IconOP extends StatelessWidget { class ButtonOP extends StatelessWidget { final String op; final RxString curOP; - final double iconWidth; + final String? icon; final Color primaryColor; final double height; final Function() onTap; @@ -47,7 +52,7 @@ class ButtonOP extends StatelessWidget { Key? key, required this.op, required this.curOP, - required this.iconWidth, + required this.icon, required this.primaryColor, required this.height, required this.onTap, @@ -71,15 +76,15 @@ class ButtonOP extends StatelessWidget { SizedBox( width: 30, child: _IconOP( - icon: op, - iconWidth: iconWidth, + op: op, + icon: icon, margin: EdgeInsets.only(right: 5), )), Expanded( child: FittedBox( fit: BoxFit.scaleDown, child: Center( - child: Text('${translate("Continue with")} $op')))), + child: Text('${translate("Continue with")} ${toCapitalized(op)}')))), ], ))), ), @@ -89,8 +94,8 @@ class ButtonOP extends StatelessWidget { class ConfigOP { final String op; - final double iconWidth; - ConfigOP({required this.op, required this.iconWidth}); + final String? icon; + ConfigOP({required this.op, required this.icon}); } class WidgetOP extends StatefulWidget { @@ -182,7 +187,7 @@ class _WidgetOPState extends State { ButtonOP( op: widget.config.op, curOP: widget.curOP, - iconWidth: widget.config.iconWidth, + icon: widget.config.icon, primaryColor: str2color(widget.config.op, 0x7f), height: 36, onTap: () async { @@ -380,7 +385,7 @@ Future loginDialog() async { final loginOptions = [].obs; Future.delayed(Duration.zero, () async { - loginOptions.value = await UserModel.queryLoginOptions(); + loginOptions.value = await UserModel.queryOidcLoginOptions(); }); final res = await gFFI.dialogManager.show((setState, close, context) { @@ -460,12 +465,8 @@ Future loginDialog() async { } thirdAuthWidget() => Obx(() { - final oidcOptions = loginOptions - .where((opt) => opt.startsWith(kAuthReqTypeOidc)) - .map((opt) => opt.substring(kAuthReqTypeOidc.length)) - .toList(); return Offstage( - offstage: oidcOptions.isEmpty, + offstage: loginOptions.isEmpty, child: Column( children: [ const SizedBox( @@ -480,12 +481,8 @@ Future loginDialog() async { height: 8.0, ), LoginWidgetOP( - ops: [ - ConfigOP(op: 'GitHub', iconWidth: 20), - ConfigOP(op: 'Google', iconWidth: 20), - ConfigOP(op: 'Okta', iconWidth: 38), - ] - .where((op) => oidcOptions.contains(op.op.toLowerCase())) + ops: loginOptions + .map((e) => ConfigOP(op: e['name'], icon: e['icon'])) .toList(), curOP: curOP, cbLogin: (Map authBody) { diff --git a/flutter/lib/models/user_model.dart b/flutter/lib/models/user_model.dart index 83df2e632..18f409608 100644 --- a/flutter/lib/models/user_model.dart +++ b/flutter/lib/models/user_model.dart @@ -163,15 +163,15 @@ class UserModel { return loginResponse; } - static Future> queryLoginOptions() async { + static Future> queryOidcLoginOptions() async { try { final url = await bind.mainGetApiServer(); if (url.trim().isEmpty) return []; - final resp = await http.get(Uri.parse('$url/api/login-options')); + final resp = await http.get(Uri.parse('$url/api/oidc/login-options')); return jsonDecode(resp.body); } catch (e) { debugPrint( - "queryLoginOptions: jsonDecode resp body failed: ${e.toString()}"); + "queryOidcLoginOptions: jsonDecode resp body failed: ${e.toString()}"); return []; } }