Skip to content

home: Show organization name and icon atop main menu #1313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
"@switchAccountButton": {
"description": "Label for main-menu button leading to the choose-account page."
},
"organizationsButtonLabel": "Organizations",
"@organizationsButtonLabel": {
"description": "Button text to view and switch between different organizations."
},
"tryAnotherAccountMessage": "Your account at {url} is taking a while to load.",
"@tryAnotherAccountMessage": {
"description": "Message that appears on the loading screen after waiting for some time.",
Expand Down
5 changes: 5 additions & 0 deletions lib/api/model/initial_snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class InitialSnapshot {

final bool realmMandatoryTopics;

final String realmName;
/// The number of days until a user's account is treated as a full member.
///
/// Search for "realm_waiting_period_threshold" in https://zulip.com/api/register-queue.
Expand All @@ -81,6 +82,8 @@ class InitialSnapshot {

final Map<String, RealmDefaultExternalAccount> realmDefaultExternalAccounts;

final String realmIconUrl;

final int maxFileUploadSizeMib;

final Uri? serverEmojiDataUrl; // TODO(server-6)
Expand Down Expand Up @@ -134,8 +137,10 @@ class InitialSnapshot {
required this.userTopics,
required this.realmWildcardMentionPolicy,
required this.realmMandatoryTopics,
required this.realmName,
required this.realmWaitingPeriodThreshold,
required this.realmDefaultExternalAccounts,
required this.realmIconUrl,
required this.maxFileUploadSizeMib,
required this.serverEmojiDataUrl,
required this.realmUsers,
Expand Down
4 changes: 4 additions & 0 deletions lib/api/model/initial_snapshot.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ abstract class ZulipLocalizations {
/// **'Switch account'**
String get switchAccountButton;

/// Button text to view and switch between different organizations.
///
/// In en, this message translates to:
/// **'Organizations'**
String get organizationsButtonLabel;

/// Message that appears on the loading screen after waiting for some time.
///
/// In en, this message translates to:
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
@override
String get switchAccountButton => 'Switch account';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Your account at $url is taking a while to load.';
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
@override
String get switchAccountButton => 'Switch account';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Your account at $url is taking a while to load.';
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
@override
String get switchAccountButton => 'Switch account';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Your account at $url is taking a while to load.';
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_nb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
@override
String get switchAccountButton => 'Switch account';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Your account at $url is taking a while to load.';
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_pl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
@override
String get switchAccountButton => 'Przełącz konto';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Twoje konto na $url wymaga jeszcze chwili na załadowanie.';
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
@override
String get switchAccountButton => 'Сменить учетную запись';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Ваша учетная запись на $url загружается медленно.';
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_sk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
@override
String get switchAccountButton => 'Zmeniť účet';

@override
String get organizationsButtonLabel => 'Organizations';

@override
String tryAnotherAccountMessage(Object url) {
return 'Načítavanie vášho konta na adrese $url chvílu trvá.';
Expand Down
9 changes: 9 additions & 0 deletions lib/model/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,17 @@ class PerAccountStore extends ChangeNotifier with EmojiStore, ChannelStore, Mess
assert(connection.zulipFeatureLevel == account.zulipFeatureLevel);

final realmUrl = account.realmUrl;
final realmName = initialSnapshot.realmName;
final realmIcon = initialSnapshot.realmIconUrl;
final channels = ChannelStoreImpl(initialSnapshot: initialSnapshot);
return PerAccountStore._(
globalStore: globalStore,
connection: connection,
realmUrl: realmUrl,
realmWildcardMentionPolicy: initialSnapshot.realmWildcardMentionPolicy,
realmMandatoryTopics: initialSnapshot.realmMandatoryTopics,
realmName: realmName,
realmIcon: realmIcon,
realmWaitingPeriodThreshold: initialSnapshot.realmWaitingPeriodThreshold,
maxFileUploadSizeMib: initialSnapshot.maxFileUploadSizeMib,
realmDefaultExternalAccounts: initialSnapshot.realmDefaultExternalAccounts,
Expand Down Expand Up @@ -315,6 +319,8 @@ class PerAccountStore extends ChangeNotifier with EmojiStore, ChannelStore, Mess
required this.realmUrl,
required this.realmWildcardMentionPolicy,
required this.realmMandatoryTopics,
required this.realmName,
required this.realmIcon,
required this.realmWaitingPeriodThreshold,
required this.maxFileUploadSizeMib,
required this.realmDefaultExternalAccounts,
Expand Down Expand Up @@ -373,6 +379,9 @@ class PerAccountStore extends ChangeNotifier with EmojiStore, ChannelStore, Mess
/// Always equal to `account.realmUrl` and `connection.realmUrl`.
final Uri realmUrl;

final String realmName;
final String realmIcon;

/// Resolve [reference] as a URL relative to [realmUrl].
///
/// This returns null if [reference] fails to parse as a URL.
Expand Down
79 changes: 79 additions & 0 deletions lib/widgets/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ void _showMainMenu(BuildContext context, {
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
_OrganizationHeader(),
Flexible(child: InsetShadowBox(
top: 8, bottom: 8,
color: designVariables.bgBotBar,
Expand All @@ -326,6 +327,84 @@ void _showMainMenu(BuildContext context, {
});
}

class _OrganizationHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
final store = PerAccountStoreWidget.of(context);
final designVariables = DesignVariables.of(context);
final zulipLocalizations = ZulipLocalizations.of(context);

String organizationName = store.realmName;
Uri? organizationIcon = store.tryResolveUrl(store.realmIcon);
final buttonStyle = TextButton.styleFrom(
splashFactory: NoSplash.splashFactory,
overlayColor: Colors.transparent
);

return Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Image.network(
organizationIcon.toString(),
width: 28,
height: 28,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return const SizedBox(
width: 28,
height: 28,
child: Placeholder(),
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const SizedBox(
width: 28,
height: 28,
child: CircularProgressIndicator(),
);
},
),
const SizedBox(width: 8),
Expanded(
child: Text(
organizationName,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
),
TextButton(
onPressed: () {
Navigator.of(context).push(MaterialWidgetRoute(page: const ChooseAccountPage()));
},
style: buttonStyle,
child: Text(
zulipLocalizations.organizationsButtonLabel,
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.w500,
color: designVariables.icon,
),
),
),
],
),
);
}
}

abstract class _MenuButton extends StatelessWidget {
const _MenuButton();

Expand Down
4 changes: 4 additions & 0 deletions test/example_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -856,10 +856,12 @@ InitialSnapshot initialSnapshot({
List<ZulipStream>? streams,
UserSettings? userSettings,
List<UserTopicItem>? userTopics,
String? realmName,
RealmWildcardMentionPolicy? realmWildcardMentionPolicy,
bool? realmMandatoryTopics,
int? realmWaitingPeriodThreshold,
Map<String, RealmDefaultExternalAccount>? realmDefaultExternalAccounts,
String? realmIconUrl,
int? maxFileUploadSizeMib,
Uri? serverEmojiDataUrl,
List<User>? realmUsers,
Expand Down Expand Up @@ -892,10 +894,12 @@ InitialSnapshot initialSnapshot({
emojiset: Emojiset.google,
),
userTopics: userTopics,
realmName: realmName ?? "Example Name",
realmWildcardMentionPolicy: realmWildcardMentionPolicy ?? RealmWildcardMentionPolicy.everyone,
realmMandatoryTopics: realmMandatoryTopics ?? true,
realmWaitingPeriodThreshold: realmWaitingPeriodThreshold ?? 0,
realmDefaultExternalAccounts: realmDefaultExternalAccounts ?? {},
realmIconUrl: realmIconUrl ?? "https://example.com/image.png",
maxFileUploadSizeMib: maxFileUploadSizeMib ?? 25,
serverEmojiDataUrl: serverEmojiDataUrl
?? realmUrl.replace(path: '/static/emoji.json'),
Expand Down
18 changes: 18 additions & 0 deletions test/widgets/home_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,24 @@ void main () {
check(find.byType(BottomSheet)).findsNothing();
});

testWidgets('organization header shows realm info and navigation works', (tester) async {
await prepare(tester);
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
await tapOpenMenu(tester);

check(find.text(store.realmName)).findsOne();
check(find.byType(Image)).findsOne();

final organizationsButton = find.text('Organizations');
check(organizationsButton).findsOne();

await tester.tap(organizationsButton);
await tester.pump(Duration.zero);
await tester.pump(const Duration(milliseconds: 250)); // wait for animation

check(find.byType(ChooseAccountPage)).findsOne();
});

testWidgets('_MyProfileButton', (tester) async {
await prepare(tester);
await tapOpenMenu(tester);
Expand Down