Skip to content

Support some client settings; add settings page #1167

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

Merged
merged 7 commits into from
Mar 11, 2025
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
Binary file modified assets/icons/ZulipIcons.ttf
Binary file not shown.
4 changes: 4 additions & 0 deletions assets/icons/settings.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
"@chooseAccountPageTitle": {
"description": "Title for the page to choose between Zulip accounts."
},
"settingsPageTitle": "Settings",
"@settingsPageTitle": {
"description": "Title for the settings page."
},
"switchAccountButton": "Switch account",
"@switchAccountButton": {
"description": "Label for main-menu button leading to the choose-account page."
Expand Down Expand Up @@ -791,6 +795,22 @@
"voterNames": {"type": "String", "example": "Alice, Bob, Chad"}
}
},
"themeSettingTitle": "THEME",
"@themeSettingTitle": {
"description": "Title for theme setting. (Use ALL CAPS for cased alphabets: Latin, Greek, Cyrillic, etc.)"
},
"themeSettingDark": "Dark",
"@themeSettingDark": {
"description": "Label for dark theme setting."
},
"themeSettingLight": "Light",
"@themeSettingLight": {
"description": "Label for light theme setting."
},
"themeSettingSystem": "System",
"@themeSettingSystem": {
"description": "Label for system theme setting."
},
"pollWidgetQuestionMissing": "No question.",
"@pollWidgetQuestionMissing": {
"description": "Text to display for a poll when the question is missing"
Expand Down
30 changes: 30 additions & 0 deletions lib/generated/l10n/zulip_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ abstract class ZulipLocalizations {
/// **'Choose account'**
String get chooseAccountPageTitle;

/// Title for the settings page.
///
/// In en, this message translates to:
/// **'Settings'**
String get settingsPageTitle;

/// Label for main-menu button leading to the choose-account page.
///
/// In en, this message translates to:
Expand Down Expand Up @@ -1155,6 +1161,30 @@ abstract class ZulipLocalizations {
/// **'({voterNames})'**
String pollVoterNames(String voterNames);

/// Title for theme setting. (Use ALL CAPS for cased alphabets: Latin, Greek, Cyrillic, etc.)
///
/// In en, this message translates to:
/// **'THEME'**
String get themeSettingTitle;

/// Label for dark theme setting.
///
/// In en, this message translates to:
/// **'Dark'**
String get themeSettingDark;

/// Label for light theme setting.
///
/// In en, this message translates to:
/// **'Light'**
String get themeSettingLight;

/// Label for system theme setting.
///
/// In en, this message translates to:
/// **'System'**
String get themeSettingSystem;

/// Text to display for a poll when the question is missing
///
/// In en, this message translates to:
Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'Choose account';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Switch account';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'No question.';

Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'Choose account';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Switch account';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'No question.';

Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'アカウントを選択';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Switch account';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'No question.';

Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_nb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'Choose account';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Switch account';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'No question.';

Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_pl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'Wybierz konto';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Przełącz konto';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'Brak pytania.';

Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'Выберите учетную запись';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Сменить учетную запись';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'Нет вопроса.';

Expand Down
15 changes: 15 additions & 0 deletions lib/generated/l10n/zulip_localizations_sk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
@override
String get chooseAccountPageTitle => 'Zvoliť účet';

@override
String get settingsPageTitle => 'Settings';

@override
String get switchAccountButton => 'Zmeniť účet';

Expand Down Expand Up @@ -619,6 +622,18 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
return '($voterNames)';
}

@override
String get themeSettingTitle => 'THEME';

@override
String get themeSettingDark => 'Dark';

@override
String get themeSettingLight => 'Light';

@override
String get themeSettingSystem => 'System';

@override
String get pollWidgetQuestionMissing => 'Bez otázky.';

Expand Down
4 changes: 2 additions & 2 deletions lib/model/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ abstract class ZulipBinding {
}

/// Get the app's singleton [GlobalStore],
/// calling [loadGlobalStore] if not already loaded.
/// loading it asynchronously if not already loaded.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

store [nfc]: Update outdated references to loadGlobalStore

commit-message nit: truncate commit ID to 9 characters

///
/// Where possible, use [GlobalStoreWidget.of] to get access to a [GlobalStore].
/// Use this method only in contexts like notifications where
Expand Down Expand Up @@ -312,7 +312,7 @@ class PackageInfo {

/// A concrete binding for use in the live application.
///
/// The global store returned by [loadGlobalStore], and consequently by
/// The global store returned by [getGlobalStore], and consequently by
/// [GlobalStoreWidget.of] in application code, will be a [LiveGlobalStore].
/// It therefore uses a live server and live, persistent local database.
///
Expand Down
40 changes: 38 additions & 2 deletions lib/model/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@ import 'package:sqlite3/common.dart';

import '../log.dart';
import 'schema_versions.g.dart';
import 'settings.dart';

part 'database.g.dart';

/// The table of the user's chosen settings independent of account, on this
/// client.
///
/// These apply across all the user's accounts on this client (i.e. on this
/// install of the app on this device).
@DataClassName('GlobalSettingsData')
class GlobalSettings extends Table {
Column<String> get themeSetting => textEnum<ThemeSetting>()
.nullable()();
}

/// The table of [Account] records in the app's database.
class Accounts extends Table {
/// The ID of this account in the app's local database.
Expand Down Expand Up @@ -59,12 +71,14 @@ VersionedSchema _getSchema({
switch (schemaVersion) {
case 2:
return Schema2(database: database);
case 3:
return Schema3(database: database);
default:
throw Exception('unknown schema version: $schemaVersion');
}
}

@DriftDatabase(tables: [Accounts])
@DriftDatabase(tables: [GlobalSettings, Accounts])
class AppDatabase extends _$AppDatabase {
AppDatabase(super.e);

Expand All @@ -79,7 +93,7 @@ class AppDatabase extends _$AppDatabase {
// * Write a migration in `onUpgrade` below.
// * Write tests.
@override
int get schemaVersion => 2; // See note.
int get schemaVersion => 3; // See note.

Future<void> _dropAndCreateAll(Migrator m, {
required int schemaVersion,
Expand Down Expand Up @@ -128,10 +142,32 @@ class AppDatabase extends _$AppDatabase {
from1To2: (m, schema) async {
await m.addColumn(schema.accounts, schema.accounts.ackedPushToken);
},
from2To3: (m, schema) async {
await m.createTable(schema.globalSettings);
},
));
});
}

Future<GlobalSettingsData> ensureGlobalSettings() async {
final settings = await select(globalSettings).get();
// TODO(db): Enforce the singleton constraint more robustly.
if (settings.isNotEmpty) {
if (settings.length > 1) {
assert(debugLog('Expected one globalSettings, got multiple: $settings'));
}
return settings.first;
}

final rowsAffected = await into(globalSettings).insert(GlobalSettingsCompanion.insert());
assert(rowsAffected == 1);
final result = await select(globalSettings).get();
if (result.length > 1) {
assert(debugLog('Expected one globalSettings, got multiple: $result'));
}
return result.first;
}

Future<int> createAccount(AccountsCompanion values) async {
try {
return await into(accounts).insert(values);
Expand Down
Loading