Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/sso/microsoft.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,7 @@
"privacyNoticeTitle": "Bevor es weitergeht",
"privacyNoticeContinue": "Weiter",
"privacyNoticeSignOut": "Abmelden",
"privacyNoticeFailed": "Das hat nicht geklappt. Versuche es nochmals."
"privacyNoticeFailed": "Das hat nicht geklappt. Versuche es nochmals.",
"signInWithMicrosoft": "Mit Microsoft anmelden",
"trademarkNotice": "Microsoft 365, Microsoft Outlook, Microsoft Teams, Microsoft OneDrive und Microsoft OneNote sind Marken der Microsoft Corporation. Schulnetz ist eine Marke der Centerboard AG. Schuly ist ein unabhängiges Projekt und steht in keiner Verbindung zu Microsoft oder Centerboard."
}
10 changes: 9 additions & 1 deletion lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -358,5 +358,13 @@
"privacyNoticeTitle": "Before you continue",
"privacyNoticeContinue": "Continue",
"privacyNoticeSignOut": "Sign out",
"privacyNoticeFailed": "That did not work. Try again."
"privacyNoticeFailed": "That did not work. Try again.",
"signInWithMicrosoft": "Sign in with Microsoft",
"@signInWithMicrosoft": {
"description": "Label of the Sign in with Microsoft button, in Microsoft's own wording"
},
"trademarkNotice": "Microsoft 365, Microsoft Outlook, Microsoft Teams, Microsoft OneDrive and Microsoft OneNote are trademarks of Microsoft Corporation. Schulnetz is a trademark of Centerboard AG. Schuly is an independent project and is not affiliated with Microsoft or Centerboard.",
"@trademarkNotice": {
"description": "Trademark notice under About in Settings"
}
}
64 changes: 64 additions & 0 deletions lib/ui/auth/microsoft_sign_in_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:forui/forui.dart';

import '../../l10n/app_localizations.dart';
import '../../services/auth_service.dart';

/// Microsoft providers get the branded button. The server names their icon `/sso-icons/microsoft.svg`
/// (older servers `.png`).
bool isMicrosoftProvider(SignInProvider provider) {
final path = Uri.tryParse(provider.iconUrl ?? '')?.path.toLowerCase() ?? '';
return provider.key.toLowerCase() == 'microsoft' || path.endsWith('/sso-icons/microsoft.svg') || path.endsWith('/sso-icons/microsoft.png');
}

/// The "Sign in with Microsoft" button as Microsoft's branding guidelines specify it
/// (learn.microsoft.com/entra/identity-platform/howto-add-branding-in-apps): the official logo SVG at 21,
/// 41 high, 12 padding and 12 between logo and text, Segoe UI 15 weight 600, square corners.
/// Light: #FFFFFF with a 1 #8C8C8C border and #5E5E5E text. Dark: #2F2F2F with #FFFFFF text.
class MicrosoftSignInButton extends StatelessWidget {
const MicrosoftSignInButton({super.key, required this.onPress});

final VoidCallback? onPress;

@override
Widget build(BuildContext context) {
final dark = context.theme.colors.brightness == Brightness.dark;
final background = dark ? const Color(0xFF2F2F2F) : const Color(0xFFFFFFFF);
final border = dark ? const Color(0xFF2F2F2F) : const Color(0xFF8C8C8C);
final text = dark ? const Color(0xFFFFFFFF) : const Color(0xFF5E5E5E);
final label = AppLocalizations.of(context)!.signInWithMicrosoft;

return Center(
child: Semantics(
button: true,
enabled: onPress != null,
label: label,
excludeSemantics: true,
child: Opacity(
opacity: onPress == null ? 0.6 : 1,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onPress,
child: Container(
height: 41,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(color: background, border: Border.all(color: border)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset('assets/sso/microsoft.svg', width: 21, height: 21),
const SizedBox(width: 12),
Text(
label,
style: TextStyle(fontFamily: 'Segoe UI', fontFamilyFallback: const ['Roboto', '.SF UI Text'], fontSize: 15, fontWeight: FontWeight.w600, color: text, height: 1),
),
],
),
),
),
),
),
);
}
}
4 changes: 4 additions & 0 deletions lib/ui/auth/sign_in_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../../l10n/app_localizations.dart';
import '../../services/auth_service.dart';
import '../update/check_for_updates.dart';
import '../widgets/remote_icon.dart';
import 'microsoft_sign_in_button.dart';
import '../privacy/privacy_notice_screen.dart';

enum _Step { signIn, register, code, verifyEmail, forgot }
Expand Down Expand Up @@ -377,6 +378,9 @@ class _SignInScreenState extends State<SignInScreen> {
),
if (_step == _Step.signIn) ...[
for (final provider in _providers)
if (isMicrosoftProvider(provider))
MicrosoftSignInButton(onPress: _busy ? null : () => _signInWith(provider))
else
FButton(
style: FButtonStyle.outline(),
onPress: _busy ? null : () => _signInWith(provider),
Expand Down
8 changes: 8 additions & 0 deletions lib/ui/settings/settings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:forui/forui.dart';
import 'package:url_launcher/url_launcher.dart';

import '../../config/backend_config.dart';
import '../../l10n/app_localizations.dart';
import '../../services/active_account_service.dart';
import '../../services/app_mode_service.dart';
import '../../services/auth_service.dart';
Expand Down Expand Up @@ -128,6 +129,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
applicationName: 'Schuly',
),
),
Padding(
padding: const EdgeInsets.fromLTRB(4, 12, 4, 0),
child: Text(
AppLocalizations.of(context)!.trademarkNotice,
style: context.theme.typography.xs.copyWith(color: context.theme.colors.mutedForeground),
),
),
],
),
);
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ flutter:
- assets/schuly_icon.png
- assets/cropped_schuly_icon.png
- assets/schoolsystems/
- assets/sso/

# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
Expand Down
Loading