From 4f7b1d4520092ccb4b417df7098e96f150b56b17 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Fri, 2 Sep 2022 14:35:25 +0100 Subject: [PATCH] feat: overall UI rework in Settings View (#53) --- assets/i18n/en.json | 38 +-- assets/images/github.png | Bin 1714 -> 0 bytes assets/images/twitter.png | Bin 19901 -> 0 bytes assets/images/youtube.png | Bin 7418 -> 0 bytes lib/theme.dart | 2 + .../views/app_selector/app_selector_view.dart | 2 +- .../views/contributors/contributors_view.dart | 2 +- lib/ui/views/home/home_view.dart | 41 +--- lib/ui/views/installer/installer_view.dart | 45 +--- lib/ui/views/patcher/patcher_view.dart | 35 +-- .../patches_selector_view.dart | 2 +- .../views/root_checker/root_checker_view.dart | 6 +- lib/ui/views/settings/settings_view.dart | 230 ++++++++---------- lib/ui/views/settings/settings_viewmodel.dart | 23 +- .../appSelectorView/installed_app_item.dart | 4 +- .../contributorsView/contributors_card.dart | 2 +- .../homeView/available_updates_card.dart | 4 +- .../widgets/homeView/dashboard_raw_chip.dart | 5 +- .../widgets/homeView/installed_apps_card.dart | 2 +- .../widgets/homeView/latest_commit_card.dart | 8 +- .../installerView/custom_material_button.dart | 7 +- .../patcherView/app_selector_card.dart | 4 +- .../patcherView/patch_selector_card.dart | 2 +- .../patchesSelectorView/patch_item.dart | 10 +- .../rootCheckerView/magisk_button.dart | 4 +- ...out_info_widget.dart => about_widget.dart} | 8 +- .../widgets/settingsView/custom_switch.dart | 6 +- ...itch_item.dart => custom_switch_tile.dart} | 21 +- .../settingsView/custom_text_field.dart | 46 ++-- .../settingsView/settings_section.dart | 38 +++ .../settingsView/settings_tile_dialog.dart | 39 +++ ...ia_cards.dart => social_media_widget.dart} | 82 +++---- .../widgets/settingsView/sources_widget.dart | 80 ++++++ lib/ui/widgets/shared/application_item.dart | 6 +- .../widgets/shared/custom_sliver_app_bar.dart | 39 +++ lib/ui/widgets/shared/search_bar.dart | 2 +- pubspec.yaml | 1 + 37 files changed, 485 insertions(+), 361 deletions(-) delete mode 100644 assets/images/github.png delete mode 100644 assets/images/twitter.png delete mode 100644 assets/images/youtube.png rename lib/ui/widgets/settingsView/{about_info_widget.dart => about_widget.dart} (94%) rename lib/ui/widgets/settingsView/{settings_switch_item.dart => custom_switch_tile.dart} (54%) create mode 100644 lib/ui/widgets/settingsView/settings_section.dart create mode 100644 lib/ui/widgets/settingsView/settings_tile_dialog.dart rename lib/ui/widgets/settingsView/{social_media_cards.dart => social_media_widget.dart} (63%) create mode 100644 lib/ui/widgets/settingsView/sources_widget.dart create mode 100644 lib/ui/widgets/shared/custom_sliver_app_bar.dart diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 713f1655..e0f3a806 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -11,7 +11,7 @@ "patchedSubtitle": "Patched Applications", "updatesAvailable": "Updates Available", "noUpdates": "No updates available", - "noInstallations": "No patched apps installed", + "noInstallations": "No patched applications installed", "installed": "Installed", "notificationTitle": "ReVanced Manager was updated!", "notificationText": "Tap to open the app", @@ -40,7 +40,7 @@ "widgetTitle": "Select application", "widgetTitleSelected": "Selected application", "widgetSubtitle": "No application selected.", - "noAppsLabel": "No apps found." + "noAppsLabel": "No applications found." }, "patchSelectorCard": { "widgetTitle": "Select patches", @@ -48,8 +48,16 @@ "widgetSubtitle": "Select an application first.", "widgetEmptySubtitle": "No patches selected." }, - "socialMediaCards": { - "widgetTitle": "Social Media" + "socialMediaCard": { + "widgetTitle": "Social Media", + "widgetSubtitle": "We are online!" + }, + "sourcesCard": { + "widgetTitle": "Sources", + "widgetSubtitle": "Add your custom sources", + "organizationLabel": "Organization", + "patchesSourceLabel" : "Patches Source", + "integrationsSourceLabel": "Integrations Source" }, "appSelectorView": { "searchBarHint": "Search applications", @@ -75,19 +83,21 @@ }, "settingsView": { "widgetTitle": "Settings", - "languageLabel": "Language", + "appearanceSectionTitle": "Appearance", + "patcherSectionTitle": "Patcher", + "teamSectionTitle": "Team", + "infoSectionTitle": "Info", "themeLabel": "Theme", "themeHint": "Change the theme of the app", - "darkThemeLabel": "Dark", - "lightThemeLabel": "Light", - "versionLabel": "Version", - "aboutLabel": "About", - "contributorsLabel": "Contributors", + "languageLabel": "Language", + "englishOption": "English", + "frenchOption": "French", "rootModeLabel": "Root Mode", - "rootModeHint": "Enable this if you want to patch applications as rooted.", - "organizationLabel": "Organization", - "patchesSourceLabel" : "Patches Source", - "integrationsSourceLabel": "Integrations Source" + "rootModeHint": "Do you want to patch applications as rooted?", + "contributorsLabel": "Contributors", + "contributorsHint": "A list of contributors of ReVanced", + "aboutLabel": "About", + "versionLabel": "Version" }, "rootCheckerView": { "widgetTitle": "Is your device rooted?", diff --git a/assets/images/github.png b/assets/images/github.png deleted file mode 100644 index 8b25551a97921681334176ee143b41510a117d86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1714 zcmaJ?X;2eq7*4oFu!ne{XxAht2qc?8LXr|_LPCfTpaBK7K$c{I0Ld=NLIOeuC;@2) zZ$K%a)k+m-s0>xHmKxL%0V&0TRzzznhgyqrIC$F)0{WwLXLrBvd*^wc_uSc%h%m9E z{W5z3f#4_!7RvAyFh6!S_*<8qJ%KOIm?#E|L=rJQq=gB5C6WLG5;c?r%V0>EmEH#X z5eSwPRa6WXBMs#$5H%GtW2go-in9p>zW@UYDNNWc^XOXZQ? z1QjEV00I#$3^1wQUJ8&-2UsjB-G|9y(LDhMNN3PM{APL4eYi{(m*ERcUnJa{R+-3^ z34^A6;U^v`8N*O6ji%S@sd{fJqD`XFIUJ5zgTe5^5nj414F(y!G&=H(f)Lgzv?>%+ zAsWD}2qhpH7>|TU`X&W6IxDNuO_vET7|j5oG&&VDr!)hUO8+0KR?nh!m<)a!?|%yG zqOwq!CWCcIhE{<$E|F|@g>nP6FoYr6C<8>D?ID9%&5J(4oSbR1I^byW*g@__U z4QsF&uJSEcFeleM3~ChjEQGbHOjsGDMbyAl(p=Ttv9RaVo8~I#js@@Y9C^_2U})yn zzSHU%6FxuY?d;&65MyR({^lU*3$z$ZllDb(o&<7d;A_`h2U+3~BJ2Hv`{W}KEU801#cv_B|9Cm!ynR{S`AMsSn z;7E=B;mb!wx$L;S>yGXG^6=&WlQn9$s?&L%Y1D8TI^MlKB1DqsEng$>f4=xYWBoPI z_S1p!sJ#d2?YI4kPA{k}Eby?F=f-J9zIc`YDl^pzjVm~9ebE?Hn?t0Nx+la|D0MB; z9)2xv1G>a1|A9kQ>~DV<=X3-4yC&n!m8-3K#P z{X@0zRuQsy$+N ziSCoLJU{Z$nQy4A4Y5UJ07$5FA~qL2%Q+cLaqDU?Lz3?=BC5;Nk6BbTmmceEaM>-Z zi>O&-dSE=%ex;vcvCOk{*JQ5^_4M z4lW7%l9IqY(z7pV(?I@@8=KPFO82)O{VDI18-*d-k$YmI^XiuPs_LuFw<^ZcD}yP5 c*NrbeloN*74g`U%%F6r~k%+>C^#XapzmV0H-2eap diff --git a/assets/images/twitter.png b/assets/images/twitter.png deleted file mode 100644 index 040ca16995674eb360877c7e9cfb2e5d797e7e8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19901 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 e4P?8Kwqc&VkbpVt~-Wz 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 { ), ) : Column( - children: [ + children: [ SearchBar( showSelectIcon: false, fillColor: isDark diff --git a/lib/ui/views/contributors/contributors_view.dart b/lib/ui/views/contributors/contributors_view.dart index 459b7a1f..49045a55 100644 --- a/lib/ui/views/contributors/contributors_view.dart +++ b/lib/ui/views/contributors/contributors_view.dart @@ -15,7 +15,7 @@ class ContributorsView extends StatelessWidget { body: SafeArea( child: SingleChildScrollView( child: Column( - children: [ + children: [ ContributorsCard( title: 'Patcher Contributors', contributors: model.patcherContributors, diff --git a/lib/ui/views/home/home_view.dart b/lib/ui/views/home/home_view.dart index 200d2b94..a3218d2b 100644 --- a/lib/ui/views/home/home_view.dart +++ b/lib/ui/views/home/home_view.dart @@ -8,6 +8,7 @@ import 'package:revanced_manager/ui/widgets/homeView/available_updates_card.dart import 'package:revanced_manager/ui/widgets/homeView/dashboard_raw_chip.dart'; import 'package:revanced_manager/ui/widgets/homeView/installed_apps_card.dart'; import 'package:revanced_manager/ui/widgets/homeView/latest_commit_card.dart'; +import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart'; import 'package:stacked/stacked.dart'; class HomeView extends StatelessWidget { @@ -22,32 +23,14 @@ class HomeView extends StatelessWidget { builder: (context, model, child) => Scaffold( body: CustomScrollView( slivers: [ - SliverAppBar( - pinned: true, - snap: false, - floating: false, - expandedHeight: 100.0, - automaticallyImplyLeading: false, - backgroundColor: MaterialStateColor.resolveWith( - (states) => states.contains(MaterialState.scrolledUnder) - ? isDark - ? Theme.of(context).colorScheme.primary - : Theme.of(context).navigationBarTheme.backgroundColor! - : Theme.of(context).scaffoldBackgroundColor, - ), - flexibleSpace: FlexibleSpaceBar( - titlePadding: const EdgeInsets.symmetric( - vertical: 23.0, - horizontal: 20.0, - ), - title: I18nText( - 'homeView.widgetTitle', - child: Text( - '', - style: GoogleFonts.inter( - color: Theme.of(context).textTheme.headline5!.color, - fontWeight: FontWeight.w500, - ), + CustomSliverAppBar( + title: I18nText( + 'homeView.widgetTitle', + child: Text( + '', + style: GoogleFonts.inter( + color: Theme.of(context).textTheme.headline5!.color, + fontWeight: FontWeight.w500, ), ), ), @@ -89,9 +72,9 @@ class HomeView extends StatelessWidget { ), const SizedBox(height: 8), Row( - children: [ + children: [ DashboardChip( - label: 'homeView.updatesAvailable', + label: I18nText('homeView.updatesAvailable'), isSelected: model.showUpdatableApps, onSelected: (value) { model.toggleUpdatableApps(true); @@ -99,7 +82,7 @@ class HomeView extends StatelessWidget { ), const SizedBox(width: 10), DashboardChip( - label: 'homeView.installed', + label: I18nText('homeView.installed'), isSelected: !model.showUpdatableApps, onSelected: (value) { model.toggleUpdatableApps(false); diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart index 0bba79ab..a856ab9d 100644 --- a/lib/ui/views/installer/installer_view.dart +++ b/lib/ui/views/installer/installer_view.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/installerView/custom_material_button.dart'; +import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart'; import 'package:stacked/stacked.dart'; class InstallerView extends StatelessWidget { @@ -18,32 +19,12 @@ class InstallerView extends StatelessWidget { body: CustomScrollView( controller: model.scrollController, slivers: [ - SliverAppBar( - pinned: true, - snap: false, - floating: false, - expandedHeight: 100.0, - automaticallyImplyLeading: false, - backgroundColor: MaterialStateColor.resolveWith( - (states) => states.contains(MaterialState.scrolledUnder) - ? isDark - ? Theme.of(context).colorScheme.primary - : Theme.of(context) - .navigationBarTheme - .backgroundColor! - : Theme.of(context).scaffoldBackgroundColor, - ), - flexibleSpace: FlexibleSpaceBar( - titlePadding: const EdgeInsets.symmetric( - vertical: 23.0, - horizontal: 20.0, - ), - title: Text( - model.headerLogs, - style: GoogleFonts.inter( - color: Theme.of(context).textTheme.headline5!.color, - fontWeight: FontWeight.w500, - ), + CustomSliverAppBar( + title: Text( + model.headerLogs, + style: GoogleFonts.inter( + color: Theme.of(context).textTheme.headline5!.color, + fontWeight: FontWeight.w500, ), ), bottom: PreferredSize( @@ -84,17 +65,17 @@ class InstallerView extends StatelessWidget { visible: !model.isPatching, child: Row( mainAxisAlignment: MainAxisAlignment.end, - children: [ + children: [ CustomMaterialButton( - text: 'installerView.shareButton', + label: I18nText('installerView.shareButton'), isFilled: false, onPressed: () => model.shareResult(), ), const SizedBox(width: 16), CustomMaterialButton( - text: model.isInstalled - ? 'installerView.openButton' - : 'installerView.installButton', + label: model.isInstalled + ? I18nText('installerView.openButton') + : I18nText('installerView.installButton'), isFilled: true, isExpanded: true, onPressed: () { diff --git a/lib/ui/views/patcher/patcher_view.dart b/lib/ui/views/patcher/patcher_view.dart index e8f11fb0..5d360906 100644 --- a/lib/ui/views/patcher/patcher_view.dart +++ b/lib/ui/views/patcher/patcher_view.dart @@ -9,6 +9,7 @@ import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patches_selector/patches_selector_view.dart'; import 'package:revanced_manager/ui/widgets/patcherView/app_selector_card.dart'; import 'package:revanced_manager/ui/widgets/patcherView/patch_selector_card.dart'; +import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart'; import 'package:revanced_manager/ui/widgets/shared/open_container_wrapper.dart'; import 'package:stacked/stacked.dart'; @@ -39,32 +40,14 @@ class PatcherView extends StatelessWidget { ), body: CustomScrollView( slivers: [ - SliverAppBar( - pinned: true, - snap: false, - floating: false, - expandedHeight: 100.0, - automaticallyImplyLeading: false, - backgroundColor: MaterialStateColor.resolveWith( - (states) => states.contains(MaterialState.scrolledUnder) - ? isDark - ? Theme.of(context).colorScheme.primary - : Theme.of(context).navigationBarTheme.backgroundColor! - : Theme.of(context).scaffoldBackgroundColor, - ), - flexibleSpace: FlexibleSpaceBar( - titlePadding: const EdgeInsets.symmetric( - vertical: 23.0, - horizontal: 20.0, - ), - title: I18nText( - 'patcherView.widgetTitle', - child: Text( - '', - style: GoogleFonts.inter( - color: Theme.of(context).textTheme.headline5!.color, - fontWeight: FontWeight.w500, - ), + CustomSliverAppBar( + title: I18nText( + 'patcherView.widgetTitle', + child: Text( + '', + style: GoogleFonts.inter( + color: Theme.of(context).textTheme.headline5!.color, + fontWeight: FontWeight.w500, ), ), ), diff --git a/lib/ui/views/patches_selector/patches_selector_view.dart b/lib/ui/views/patches_selector/patches_selector_view.dart index cbeb626d..052a99bc 100644 --- a/lib/ui/views/patches_selector/patches_selector_view.dart +++ b/lib/ui/views/patches_selector/patches_selector_view.dart @@ -49,7 +49,7 @@ class _PatchesSelectorViewState extends State { ), ) : Column( - children: [ + children: [ SearchBar( showSelectIcon: true, fillColor: diff --git a/lib/ui/views/root_checker/root_checker_view.dart b/lib/ui/views/root_checker/root_checker_view.dart index 895b0879..f2d311a4 100644 --- a/lib/ui/views/root_checker/root_checker_view.dart +++ b/lib/ui/views/root_checker/root_checker_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/ui/views/root_checker/root_checker_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/rootCheckerView/magisk_button.dart'; @@ -27,7 +27,7 @@ class RootCheckerView extends StatelessWidget { height: double.infinity, padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 28.0), child: Column( - children: [ + children: [ const SizedBox(height: 120), I18nText( 'rootCheckerView.widgetTitle', @@ -53,7 +53,7 @@ class RootCheckerView extends StatelessWidget { Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: [ MagiskButton( onPressed: () => model.navigateAsRoot(), ), diff --git a/lib/ui/views/settings/settings_view.dart b/lib/ui/views/settings/settings_view.dart index ffe6126f..ecb4b5cc 100644 --- a/lib/ui/views/settings/settings_view.dart +++ b/lib/ui/views/settings/settings_view.dart @@ -3,11 +3,16 @@ import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/theme.dart'; +import 'package:revanced_manager/ui/views/contributors/contributors_view.dart'; import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart'; -import 'package:revanced_manager/ui/widgets/settingsView/about_info_widget.dart'; -import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart'; -import 'package:revanced_manager/ui/widgets/settingsView/settings_switch_item.dart'; -import 'package:revanced_manager/ui/widgets/settingsView/social_media_cards.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/about_widget.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/custom_switch_tile.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/social_media_widget.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/sources_widget.dart'; +import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart'; +import 'package:revanced_manager/ui/widgets/shared/open_container_wrapper.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_themes/stacked_themes.dart'; @@ -22,149 +27,124 @@ class SettingsView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( - disposeViewModel: false, viewModelBuilder: () => SettingsViewModel(), - onModelReady: (model) => model.initialize(), builder: (context, SettingsViewModel model, child) => Scaffold( body: CustomScrollView( slivers: [ - SliverAppBar( - pinned: true, - snap: false, - floating: false, - expandedHeight: 100.0, - automaticallyImplyLeading: false, - backgroundColor: MaterialStateColor.resolveWith( - (states) => states.contains(MaterialState.scrolledUnder) - ? isDark - ? Theme.of(context).colorScheme.primary - : Theme.of(context).navigationBarTheme.backgroundColor! - : Theme.of(context).scaffoldBackgroundColor, - ), - flexibleSpace: FlexibleSpaceBar( - titlePadding: const EdgeInsets.symmetric( - vertical: 23.0, - horizontal: 20.0, - ), - title: I18nText( - 'settingsView.widgetTitle', - child: Text( - '', - style: GoogleFonts.inter( - color: Theme.of(context).textTheme.headline5!.color, - fontWeight: FontWeight.w500, - ), + CustomSliverAppBar( + title: I18nText( + 'settingsView.widgetTitle', + child: Text( + '', + style: GoogleFonts.inter( + color: Theme.of(context).textTheme.headline5!.color, + fontWeight: FontWeight.w500, ), ), ), ), SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), + padding: const EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 20.0, + ), sliver: SliverList( delegate: SliverChildListDelegate.fixed( [ - SettingsSwitchItem( - title: 'settingsView.themeLabel', - subtitle: 'settingsView.themeHint', - value: isDark, - onTap: (value) { - isDark = value; - getThemeManager(context).toggleDarkLightTheme(); - }, - ), - ListTile( - title: I18nText( - 'settingsView.rootModeLabel', - child: Text( - '', - style: kSettingItemTextStyle, - ), - ), - subtitle: I18nText('settingsView.rootModeHint'), - trailing: GestureDetector( - onTap: () { - model.navigateToRootChecker(); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, vertical: 8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - width: 1, - color: Theme.of(context).colorScheme.secondary, + SettingsSection( + title: 'settingsView.appearanceSectionTitle', + children: [ + CustomSwitchTile( + title: I18nText( + 'settingsView.themeLabel', + child: Text( + '', + style: kSettingItemTextStyle, ), ), - child: Text( - model.isRooted ? 'Rooted' : 'Not rooted', - ), + subtitle: I18nText('settingsView.themeHint'), + value: isDark, + onTap: (value) { + isDark = value; + getThemeManager(context).toggleDarkLightTheme(); + }, ), - ), + ], ), - CustomTextField( - inputController: organizationController, - label: 'settingsView.organizationLabel', - hint: ghOrg, - onChanged: (value) { - ghOrg = value; - }, - ), - CustomTextField( - inputController: patchesSourceController, - label: 'settingsView.patchesSourceLabel', - hint: patchesRepo, - onChanged: (value) { - patchesRepo = value; - }, - ), - CustomTextField( - inputController: integrationsSourceController, - label: 'settingsView.integrationsSourceLabel', - hint: integrationsRepo, - onChanged: (value) { - integrationsRepo = value; - }, - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - I18nText( - 'settingsView.languageLabel', - child: Text('', style: kSettingItemTextStyle), - ), - DropdownButton( + SettingsTileDialog( + title: 'settingsView.languageLabel', + subtitle: 'English', + children: [ + RadioListTile( + title: I18nText('settingsView.englishOption'), value: 'en', - items: const [ - DropdownMenuItem( - value: 'en', - child: Text('English'), - ), - DropdownMenuItem( - value: 'fr', - child: Text('French'), - ), - ], + groupValue: 'en', onChanged: (value) { - value = value; + model.updateLanguage(context, value); + Navigator.of(context).pop(); }, ), - ], - ), + RadioListTile( + title: I18nText('settingsView.frenchOption'), + value: 'fr', + groupValue: 'en', + onChanged: (value) { + model.updateLanguage(context, value); + Navigator.of(context).pop(); + }, + ), + ]), + const Divider(thickness: 1.0), + SettingsSection( + title: 'settingsView.patcherSectionTitle', + children: [ + ListTile( + contentPadding: EdgeInsets.zero, + title: I18nText( + 'settingsView.rootModeLabel', + child: Text( + '', + style: kSettingItemTextStyle, + ), + ), + subtitle: I18nText('settingsView.rootModeHint'), + onTap: () => model.navigateToRootChecker(), + ), + SourcesWidget( + title: 'settingsView.sourcesLabel', + organizationController: organizationController, + patchesSourceController: patchesSourceController, + integrationsSourceController: + integrationsSourceController, + ), + ], ), - ListTile( - title: I18nText( - 'settingsView.contributorsLabel', - child: Text('', style: kSettingItemTextStyle), - ), - onTap: model.navigateToContributors, + const Divider(thickness: 1.0), + SettingsSection( + title: 'settingsView.teamSectionTitle', + children: [ + OpenContainerWrapper( + openBuilder: (_, __) => const ContributorsView(), + closedBuilder: (_, openContainer) => ListTile( + contentPadding: EdgeInsets.zero, + title: I18nText( + 'settingsView.contributorsLabel', + child: Text('', style: kSettingItemTextStyle), + ), + subtitle: I18nText('settingsView.contributorsHint'), + onTap: openContainer, + ), + ), + const SocialMediaWidget(), + ], + ), + const Divider(thickness: 1.0), + const SettingsSection( + title: 'settingsView.infoSectionTitle', + children: [ + AboutWidget(), + ], ), - const SocialMediaCards(), - const AboutWidget(), ], ), ), diff --git a/lib/ui/views/settings/settings_viewmodel.dart b/lib/ui/views/settings/settings_viewmodel.dart index 96312d14..444a127e 100644 --- a/lib/ui/views/settings/settings_viewmodel.dart +++ b/lib/ui/views/settings/settings_viewmodel.dart @@ -1,29 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.router.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; +import 'package:timeago/timeago.dart'; class SettingsViewModel extends BaseViewModel { - bool isRooted = false; - - Future initialize() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - isRooted = prefs.getBool('isRooted') ?? false; - notifyListeners(); - } - final NavigationService _navigationService = locator(); void setLanguage(String language) { notifyListeners(); } - void navigateToContributors() { - _navigationService.navigateTo(Routes.contributorsView); - } - void navigateToRootChecker() { _navigationService.navigateTo(Routes.rootCheckerView); } + + Future updateLanguage(BuildContext context, String? value) async { + if (value != null) { + await FlutterI18n.refresh(context, Locale(value)); + setLocaleMessages(value, EnMessages()); + } + } } diff --git a/lib/ui/widgets/appSelectorView/installed_app_item.dart b/lib/ui/widgets/appSelectorView/installed_app_item.dart index 4278a950..126f13ec 100644 --- a/lib/ui/widgets/appSelectorView/installed_app_item.dart +++ b/lib/ui/widgets/appSelectorView/installed_app_item.dart @@ -32,7 +32,7 @@ class _InstalledAppItemState extends State { ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + children: [ Container( width: 48, height: 48, @@ -47,7 +47,7 @@ class _InstalledAppItemState extends State { Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Text( widget.name, maxLines: 2, diff --git a/lib/ui/widgets/contributorsView/contributors_card.dart b/lib/ui/widgets/contributorsView/contributors_card.dart index 869f46de..ff44866b 100644 --- a/lib/ui/widgets/contributorsView/contributors_card.dart +++ b/lib/ui/widgets/contributorsView/contributors_card.dart @@ -24,7 +24,7 @@ class _ContributorsCardState extends State { Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 4.0), child: Text( diff --git a/lib/ui/widgets/homeView/available_updates_card.dart b/lib/ui/widgets/homeView/available_updates_card.dart index 660c91be..65b05384 100644 --- a/lib/ui/widgets/homeView/available_updates_card.dart +++ b/lib/ui/widgets/homeView/available_updates_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; @@ -22,7 +22,7 @@ class AvailableUpdatesCard extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), child: Center( child: Column( - children: [ + children: [ Icon( Icons.update_disabled, size: 40, diff --git a/lib/ui/widgets/homeView/dashboard_raw_chip.dart b/lib/ui/widgets/homeView/dashboard_raw_chip.dart index 439ac69c..d715e903 100644 --- a/lib/ui/widgets/homeView/dashboard_raw_chip.dart +++ b/lib/ui/widgets/homeView/dashboard_raw_chip.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/theme.dart'; class DashboardChip extends StatelessWidget { - final String label; + final Widget label; final bool isSelected; final Function(bool)? onSelected; @@ -19,7 +18,7 @@ class DashboardChip extends StatelessWidget { Widget build(BuildContext context) { return RawChip( showCheckmark: false, - label: I18nText(label), + label: label, selected: isSelected, labelStyle: GoogleFonts.inter( color: isSelected diff --git a/lib/ui/widgets/homeView/installed_apps_card.dart b/lib/ui/widgets/homeView/installed_apps_card.dart index 6c10c1ca..f3bc0c17 100644 --- a/lib/ui/widgets/homeView/installed_apps_card.dart +++ b/lib/ui/widgets/homeView/installed_apps_card.dart @@ -23,7 +23,7 @@ class InstalledAppsCard extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), child: Center( child: Column( - children: [ + children: [ Icon( Icons.file_download_off, size: 40, diff --git a/lib/ui/widgets/homeView/latest_commit_card.dart b/lib/ui/widgets/homeView/latest_commit_card.dart index 6800116f..3265196c 100644 --- a/lib/ui/widgets/homeView/latest_commit_card.dart +++ b/lib/ui/widgets/homeView/latest_commit_card.dart @@ -32,12 +32,12 @@ class _LatestCommitCardState extends State { padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Row( - children: [ + children: [ I18nText( 'latestCommitCard.patcherLabel', child: Text( @@ -67,7 +67,7 @@ class _LatestCommitCardState extends State { ), const SizedBox(height: 8), Row( - children: [ + children: [ I18nText( 'latestCommitCard.managerLabel', child: Text( diff --git a/lib/ui/widgets/installerView/custom_material_button.dart b/lib/ui/widgets/installerView/custom_material_button.dart index 609e451b..54c884e8 100644 --- a/lib/ui/widgets/installerView/custom_material_button.dart +++ b/lib/ui/widgets/installerView/custom_material_button.dart @@ -1,16 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:revanced_manager/theme.dart'; class CustomMaterialButton extends StatelessWidget { - final String text; + final Widget label; final bool isFilled; final bool isExpanded; final Function()? onPressed; const CustomMaterialButton({ Key? key, - required this.text, + required this.label, this.isFilled = true, this.isExpanded = false, required this.onPressed, @@ -62,7 +61,7 @@ class CustomMaterialButton extends StatelessWidget { ), ), onPressed: onPressed, - child: I18nText(text), + child: label, ); } } diff --git a/lib/ui/widgets/patcherView/app_selector_card.dart b/lib/ui/widgets/patcherView/app_selector_card.dart index ea1d55fc..ee8780e0 100644 --- a/lib/ui/widgets/patcherView/app_selector_card.dart +++ b/lib/ui/widgets/patcherView/app_selector_card.dart @@ -27,7 +27,7 @@ class AppSelectorCard extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ I18nText( locator().selectedApp == null ? 'appSelectorCard.widgetTitle' @@ -50,7 +50,7 @@ class AppSelectorCard extends StatelessWidget { ), ) : Row( - children: [ + children: [ SizedBox( height: 16.0, child: ClipOval( diff --git a/lib/ui/widgets/patcherView/patch_selector_card.dart b/lib/ui/widgets/patcherView/patch_selector_card.dart index 559c391b..c19014f4 100644 --- a/lib/ui/widgets/patcherView/patch_selector_card.dart +++ b/lib/ui/widgets/patcherView/patch_selector_card.dart @@ -27,7 +27,7 @@ class PatchSelectorCard extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ I18nText( locator().selectedPatches.isEmpty ? 'patchSelectorCard.widgetTitle' diff --git a/lib/ui/widgets/patchesSelectorView/patch_item.dart b/lib/ui/widgets/patchesSelectorView/patch_item.dart index 1d6d2bc3..8d5a9de8 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_item.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_item.dart @@ -48,17 +48,17 @@ class _PatchItemState extends State { padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12), margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), child: Column( - children: [ + children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + children: [ Flexible( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Row( crossAxisAlignment: CrossAxisAlignment.end, - children: [ + children: [ Text( widget.simpleName, style: GoogleFonts.inter( @@ -98,7 +98,7 @@ class _PatchItemState extends State { ), widget.isUnsupported ? Row( - children: [ + children: [ Padding( padding: const EdgeInsets.only(top: 8), child: TextButton.icon( diff --git a/lib/ui/widgets/rootCheckerView/magisk_button.dart b/lib/ui/widgets/rootCheckerView/magisk_button.dart index f1daa71b..a59d434d 100644 --- a/lib/ui/widgets/rootCheckerView/magisk_button.dart +++ b/lib/ui/widgets/rootCheckerView/magisk_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -15,7 +15,7 @@ class MagiskButton extends StatelessWidget { Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, - children: [ + children: [ GestureDetector( onTap: onPressed, child: CircleAvatar( diff --git a/lib/ui/widgets/settingsView/about_info_widget.dart b/lib/ui/widgets/settingsView/about_widget.dart similarity index 94% rename from lib/ui/widgets/settingsView/about_info_widget.dart rename to lib/ui/widgets/settingsView/about_widget.dart index 0bc4f995..b5b274ce 100644 --- a/lib/ui/widgets/settingsView/about_info_widget.dart +++ b/lib/ui/widgets/settingsView/about_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/utils/about_info.dart'; @@ -16,10 +16,10 @@ class _AboutWidgetState extends State { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ I18nText( 'settingsView.aboutLabel', child: Text('', style: kSettingItemTextStyle), @@ -54,7 +54,7 @@ class _AboutWidgetState extends State { }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Text('Version: ${snapshot.data!['version']}', style: kSettingItemSubtitleTextStyle), Text('Build: ${snapshot.data!['buildNumber']}', diff --git a/lib/ui/widgets/settingsView/custom_switch.dart b/lib/ui/widgets/settingsView/custom_switch.dart index a8c75c15..ef936395 100644 --- a/lib/ui/widgets/settingsView/custom_switch.dart +++ b/lib/ui/widgets/settingsView/custom_switch.dart @@ -20,12 +20,12 @@ class CustomSwitch extends StatelessWidget { height: 25, width: 50, child: Stack( - children: [ + children: [ AnimatedContainer( height: 25, width: 50, curve: Curves.ease, - duration: const Duration(milliseconds: 500), + duration: const Duration(milliseconds: 400), decoration: BoxDecoration( borderRadius: const BorderRadius.all( Radius.circular(25.0), @@ -35,7 +35,7 @@ class CustomSwitch extends StatelessWidget { ), AnimatedAlign( curve: Curves.ease, - duration: const Duration(milliseconds: 500), + duration: const Duration(milliseconds: 400), alignment: !value ? Alignment.centerLeft : Alignment.centerRight, child: Container( height: 20, diff --git a/lib/ui/widgets/settingsView/settings_switch_item.dart b/lib/ui/widgets/settingsView/custom_switch_tile.dart similarity index 54% rename from lib/ui/widgets/settingsView/settings_switch_item.dart rename to lib/ui/widgets/settingsView/custom_switch_tile.dart index 956b2a31..348e1440 100644 --- a/lib/ui/widgets/settingsView/settings_switch_item.dart +++ b/lib/ui/widgets/settingsView/custom_switch_tile.dart @@ -1,15 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; -import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/ui/widgets/settingsView/custom_switch.dart'; -class SettingsSwitchItem extends StatelessWidget { - final String title; - final String subtitle; +class CustomSwitchTile extends StatelessWidget { + final Widget title; + final Widget subtitle; final bool value; final Function(bool) onTap; - const SettingsSwitchItem({ + const CustomSwitchTile({ Key? key, required this.title, required this.subtitle, @@ -20,14 +18,9 @@ class SettingsSwitchItem extends StatelessWidget { @override Widget build(BuildContext context) { return ListTile( - title: I18nText( - title, - child: Text( - '', - style: kSettingItemTextStyle, - ), - ), - subtitle: I18nText(subtitle), + contentPadding: EdgeInsets.zero, + title: title, + subtitle: subtitle, trailing: CustomSwitch( value: value, onChanged: onTap, diff --git a/lib/ui/widgets/settingsView/custom_text_field.dart b/lib/ui/widgets/settingsView/custom_text_field.dart index 270f7e75..8ea2942c 100644 --- a/lib/ui/widgets/settingsView/custom_text_field.dart +++ b/lib/ui/widgets/settingsView/custom_text_field.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/theme.dart'; class CustomTextField extends StatelessWidget { final TextEditingController inputController; - final String label; + final Widget label; final String hint; final Function(String)? onChanged; @@ -18,40 +17,42 @@ class CustomTextField extends StatelessWidget { @override Widget build(BuildContext context) { - const errorColor = Color(0xffEF4444); - return Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 8, - ), + children: [ + const SizedBox(height: 8), TextField( controller: inputController, onChanged: onChanged, keyboardType: TextInputType.text, style: TextStyle( fontSize: 14, - color: isDark ? Colors.grey[300] : Colors.black, + color: Theme.of(context).textTheme.headline5!.color, ), + cursorColor: Theme.of(context).textTheme.headline5!.color, decoration: InputDecoration( - label: I18nText(label), - labelStyle: - TextStyle(color: isDark ? Colors.grey[300] : Colors.black), + label: label, + labelStyle: TextStyle( + color: isDark ? Colors.grey[300] : Colors.black, + ), filled: true, fillColor: Theme.of(context).colorScheme.primary, hintText: hint, - hintStyle: TextStyle(color: Colors.grey.withOpacity(.75)), - contentPadding: - const EdgeInsets.symmetric(vertical: 0.0, horizontal: 20.0), + hintStyle: TextStyle( + color: Colors.grey.withOpacity(.75), + ), + contentPadding: const EdgeInsets.symmetric( + vertical: 0.0, + horizontal: 20.0, + ), border: OutlineInputBorder( borderSide: BorderSide( color: Theme.of(context).colorScheme.tertiary, width: 1.0, ), - borderRadius: const BorderRadius.all(Radius.circular(10.0)), + borderRadius: BorderRadius.circular(10), gapPadding: 4.0, ), focusedBorder: OutlineInputBorder( @@ -59,18 +60,21 @@ class CustomTextField extends StatelessWidget { color: Theme.of(context).colorScheme.secondary, width: 2.0, ), - borderRadius: const BorderRadius.all(Radius.circular(10.0)), + borderRadius: BorderRadius.circular(10), ), - errorBorder: const OutlineInputBorder( - borderSide: BorderSide(color: errorColor, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(10.0)), + errorBorder: OutlineInputBorder( + borderSide: const BorderSide( + color: Color(0xffEF4444), + width: 1.0, + ), + borderRadius: BorderRadius.circular(10), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Theme.of(context).colorScheme.tertiary, width: 1.0, ), - borderRadius: const BorderRadius.all(Radius.circular(10.0)), + borderRadius: BorderRadius.circular(10), ), ), ), diff --git a/lib/ui/widgets/settingsView/settings_section.dart b/lib/ui/widgets/settingsView/settings_section.dart new file mode 100644 index 00000000..13cb211a --- /dev/null +++ b/lib/ui/widgets/settingsView/settings_section.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; + +class SettingsSection extends StatelessWidget { + final String title; + final List children; + + const SettingsSection({ + Key? key, + required this.title, + required this.children, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.only(top: 16.0, bottom: 10.0), + child: I18nText( + title, + child: Text( + '', + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + ), + ), + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: children, + ), + ], + ); + } +} diff --git a/lib/ui/widgets/settingsView/settings_tile_dialog.dart b/lib/ui/widgets/settingsView/settings_tile_dialog.dart new file mode 100644 index 00000000..63ada5c2 --- /dev/null +++ b/lib/ui/widgets/settingsView/settings_tile_dialog.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:revanced_manager/constants.dart'; + +class SettingsTileDialog extends StatelessWidget { + final String title; + final String subtitle; + final List children; + + const SettingsTileDialog({ + Key? key, + required this.title, + required this.subtitle, + required this.children, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: EdgeInsets.zero, + title: I18nText( + title, + child: Text( + '', + style: kSettingItemTextStyle, + ), + ), + subtitle: I18nText(subtitle), + onTap: () => showDialog( + context: context, + builder: (context) => SimpleDialog( + title: I18nText(title), + backgroundColor: Theme.of(context).colorScheme.surface, + children: children, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/settingsView/social_media_cards.dart b/lib/ui/widgets/settingsView/social_media_widget.dart similarity index 63% rename from lib/ui/widgets/settingsView/social_media_cards.dart rename to lib/ui/widgets/settingsView/social_media_widget.dart index 924cf445..a2573102 100644 --- a/lib/ui/widgets/settingsView/social_media_cards.dart +++ b/lib/ui/widgets/settingsView/social_media_widget.dart @@ -1,11 +1,13 @@ import 'package:expandable/expandable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_i18n/widgets/I18nText.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:revanced_manager/constants.dart'; +import 'package:revanced_manager/theme.dart'; import 'package:url_launcher/url_launcher.dart'; -class SocialMediaCards extends StatelessWidget { - const SocialMediaCards({Key? key}) : super(key: key); +class SocialMediaWidget extends StatelessWidget { + const SocialMediaWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -13,30 +15,39 @@ class SocialMediaCards extends StatelessWidget { theme: ExpandableThemeData( hasIcon: true, iconColor: Theme.of(context).iconTheme.color, - animationDuration: const Duration(milliseconds: 450), + iconPadding: const EdgeInsets.symmetric(vertical: 16.0), + animationDuration: const Duration(milliseconds: 400), ), header: SizedBox( width: double.infinity, child: ListTile( + contentPadding: EdgeInsets.zero, title: I18nText( - 'socialMediaCards.widgetTitle', + 'socialMediaCard.widgetTitle', child: Text('', style: kSettingItemTextStyle), ), + subtitle: I18nText( + 'socialMediaCard.widgetSubtitle', + child: Text( + '', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + ), + ), ), ), expanded: Card( - color: Theme.of(context).backgroundColor, + color: isDark + ? Theme.of(context).colorScheme.primary + : Theme.of(context).navigationBarTheme.backgroundColor!, child: Column( - children: [ + children: [ ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 0), leading: Padding( padding: const EdgeInsets.all(8.0), - child: Image.asset( - 'assets/images/github.png', - height: 24, - width: 24, + child: FaIcon( + FontAwesomeIcons.github, color: Theme.of(context).iconTheme.color, ), ), @@ -48,29 +59,25 @@ class SocialMediaCards extends StatelessWidget { ), ), ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 0), leading: Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.discord, + padding: const EdgeInsets.all(8.0).copyWith(left: 5), + child: FaIcon( + FontAwesomeIcons.discord, color: Theme.of(context).iconTheme.color, ), ), title: const Text('Discord'), subtitle: const Text('discord.gg/revanced'), onTap: () => launchUrl( - Uri.parse('https://discord.gg/3E2pTWR4Yd'), + Uri.parse('https://discord.gg/rF2YcEjcrT'), mode: LaunchMode.externalApplication, ), ), ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 0), leading: Padding( padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.telegram, + child: FaIcon( + FontAwesomeIcons.telegram, color: Theme.of(context).iconTheme.color, ), ), @@ -82,12 +89,10 @@ class SocialMediaCards extends StatelessWidget { ), ), ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 0), leading: Padding( padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.reddit, + child: FaIcon( + FontAwesomeIcons.reddit, color: Theme.of(context).iconTheme.color, ), ), @@ -99,48 +104,39 @@ class SocialMediaCards extends StatelessWidget { ), ), ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 0), leading: Padding( padding: const EdgeInsets.all(8.0), - child: Image.asset( - 'assets/images/twitter.png', - height: 24, - width: 24, + child: FaIcon( + FontAwesomeIcons.twitter, color: Theme.of(context).iconTheme.color, ), ), title: const Text('Twitter'), subtitle: const Text('@revancedapp'), onTap: () => launchUrl( - Uri.parse('https://twitter.com/@revancedapp'), + Uri.parse('https://twitter.com/revancedapp'), mode: LaunchMode.externalApplication, ), ), ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 0), leading: Padding( padding: const EdgeInsets.all(8.0), - child: Image.asset( - 'assets/images/youtube.png', - height: 24, - width: 24, + child: FaIcon( + FontAwesomeIcons.youtube, color: Theme.of(context).iconTheme.color, ), ), title: const Text('YouTube'), subtitle: const Text('youtube.com/revanced'), onTap: () => launchUrl( - Uri.parse( - 'https://www.youtube.com/channel/UCLktAUh5Gza9zAJBStwxNdw'), + Uri.parse('https://youtube.com/revanced'), mode: LaunchMode.externalApplication, ), ), ], ), ), - collapsed: const Text(''), + collapsed: Container(), ); } } diff --git a/lib/ui/widgets/settingsView/sources_widget.dart b/lib/ui/widgets/settingsView/sources_widget.dart new file mode 100644 index 00000000..9d0ced7d --- /dev/null +++ b/lib/ui/widgets/settingsView/sources_widget.dart @@ -0,0 +1,80 @@ +import 'package:expandable/expandable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:revanced_manager/constants.dart'; +import 'package:revanced_manager/theme.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart'; + +class SourcesWidget extends StatelessWidget { + final String title; + final TextEditingController organizationController; + final TextEditingController patchesSourceController; + final TextEditingController integrationsSourceController; + + const SourcesWidget({ + Key? key, + required this.title, + required this.organizationController, + required this.patchesSourceController, + required this.integrationsSourceController, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ExpandablePanel( + theme: ExpandableThemeData( + hasIcon: true, + iconColor: Theme.of(context).iconTheme.color, + iconPadding: const EdgeInsets.symmetric(vertical: 16.0), + animationDuration: const Duration(milliseconds: 400), + ), + header: SizedBox( + width: double.infinity, + child: ListTile( + contentPadding: EdgeInsets.zero, + title: I18nText( + 'sourcesCard.widgetTitle', + child: Text('', style: kSettingItemTextStyle), + ), + subtitle: I18nText( + 'sourcesCard.widgetSubtitle', + child: Text( + '', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + ), + ), + ), + ), + expanded: Card( + color: isDark + ? Theme.of(context).colorScheme.primary + : Theme.of(context).navigationBarTheme.backgroundColor!, + child: Column( + children: [ + CustomTextField( + inputController: organizationController, + label: I18nText('sourcesCard.organizationLabel'), + hint: ghOrg, + onChanged: (value) => ghOrg = value, + ), + CustomTextField( + inputController: patchesSourceController, + label: I18nText('sourcesCard.patchesSourceLabel'), + hint: patchesRepo, + onChanged: (value) => patchesRepo = value, + ), + CustomTextField( + inputController: integrationsSourceController, + label: I18nText('sourcesCard.integrationsSourceLabel'), + hint: integrationsRepo, + onChanged: (value) => integrationsRepo = value, + ), + ], + ), + ), + collapsed: Container(), + ); + } +} diff --git a/lib/ui/widgets/shared/application_item.dart b/lib/ui/widgets/shared/application_item.dart index 3bfbd2d2..77a0f719 100644 --- a/lib/ui/widgets/shared/application_item.dart +++ b/lib/ui/widgets/shared/application_item.dart @@ -41,7 +41,7 @@ class ApplicationItem extends StatelessWidget { ), padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 12.0), child: Row( - children: [ + children: [ SizedBox( width: 60, child: Image.memory( @@ -55,7 +55,7 @@ class ApplicationItem extends StatelessWidget { width: MediaQuery.of(context).size.width - 250, child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Text( name, style: GoogleFonts.roboto( @@ -93,7 +93,7 @@ class ApplicationItem extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ I18nText( 'applicationItem.changelogLabel', child: Text( diff --git a/lib/ui/widgets/shared/custom_sliver_app_bar.dart b/lib/ui/widgets/shared/custom_sliver_app_bar.dart new file mode 100644 index 00000000..21b71f54 --- /dev/null +++ b/lib/ui/widgets/shared/custom_sliver_app_bar.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:revanced_manager/theme.dart'; + +class CustomSliverAppBar extends StatelessWidget { + final Widget title; + final PreferredSizeWidget? bottom; + + const CustomSliverAppBar({ + Key? key, + required this.title, + this.bottom, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverAppBar( + pinned: true, + snap: false, + floating: false, + expandedHeight: 100.0, + automaticallyImplyLeading: false, + backgroundColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.scrolledUnder) + ? isDark + ? Theme.of(context).colorScheme.primary + : Theme.of(context).navigationBarTheme.backgroundColor! + : Theme.of(context).scaffoldBackgroundColor, + ), + flexibleSpace: FlexibleSpaceBar( + titlePadding: const EdgeInsets.symmetric( + vertical: 23.0, + horizontal: 20.0, + ), + title: title, + ), + bottom: bottom, + ); + } +} diff --git a/lib/ui/widgets/shared/search_bar.dart b/lib/ui/widgets/shared/search_bar.dart index 759beb13..36ecbcda 100644 --- a/lib/ui/widgets/shared/search_bar.dart +++ b/lib/ui/widgets/shared/search_bar.dart @@ -44,7 +44,7 @@ class _SearchBarState extends State { ), ), child: Row( - children: [ + children: [ Expanded( child: TextFormField( onChanged: widget.onQueryChanged, diff --git a/pubspec.yaml b/pubspec.yaml index 6885c423..d57628f2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: flutter_local_notifications: ^9.8.0+1 flutter_svg: ^1.1.1+1 fluttertoast: ^8.0.9 + font_awesome_flutter: ^10.1.0 get_it: ^7.2.0 github: ^9.4.0 google_fonts: ^3.0.1