diff --git a/assets/svgs/ClashBot-HomePage.svg b/assets/svgs/ClashBot-HomePage.svg
new file mode 100644
index 0000000..9401f14
--- /dev/null
+++ b/assets/svgs/ClashBot-HomePage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/images/BotIcon.webp b/images/BotIcon.webp
similarity index 100%
rename from assets/images/BotIcon.webp
rename to images/BotIcon.webp
diff --git a/assets/images/JGIcon.webp b/images/JGIcon.webp
similarity index 100%
rename from assets/images/JGIcon.webp
rename to images/JGIcon.webp
diff --git a/assets/images/MidIcon.webp b/images/MidIcon.webp
similarity index 100%
rename from assets/images/MidIcon.webp
rename to images/MidIcon.webp
diff --git a/assets/images/SuppIcon.webp b/images/SuppIcon.webp
similarity index 100%
rename from assets/images/SuppIcon.webp
rename to images/SuppIcon.webp
diff --git a/assets/images/TopIcon.webp b/images/TopIcon.webp
similarity index 100%
rename from assets/images/TopIcon.webp
rename to images/TopIcon.webp
diff --git a/lib/globals/credentials.dart b/lib/globals/credentials.dart
index dad01de..080c944 100644
--- a/lib/globals/credentials.dart
+++ b/lib/globals/credentials.dart
@@ -1,7 +1,9 @@
import 'dart:io';
+
abstract class Credentials {
- static const APP_DISCORD_OAUTH_CLIENT_ID = "837629412328734740";
- static const APP_DISCORD_OAUTH_REDIRECT_URI = "http://localhost:4200/login";
- static const SCOPE = ['identify', 'guilds'];
- static final appUserCredentialsFile = new File("~/.myapp/credentials.json");
-}
\ No newline at end of file
+ // static const APP_DISCORD_OAUTH_CLIENT_ID = "837629412328734740";
+ static const APP_DISCORD_OAUTH_CLIENT_ID = "839586949748228156";
+ static const APP_DISCORD_OAUTH_REDIRECT_URI = "http://localhost:4200/login";
+ static const SCOPE = ['identify', 'guilds'];
+ static final appUserCredentialsFile = new File("~/.myapp/credentials.json");
+}
diff --git a/lib/globals/global_settings.dart b/lib/globals/global_settings.dart
index ffe2ae6..6d622eb 100644
--- a/lib/globals/global_settings.dart
+++ b/lib/globals/global_settings.dart
@@ -1,5 +1,4 @@
import 'package:clashbot_flutter/clients/discord_client.dart';
-import 'package:clashbot_flutter/clients/mock_discord_client.dart';
import 'package:clashbot_flutter/globals/credentials.dart';
import 'package:oauth2_client/oauth2_helper.dart';
diff --git a/lib/main.dart b/lib/main.dart
index c28acf3..d43c203 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -3,8 +3,10 @@ import 'dart:developer' as developer;
import 'package:clash_bot_api/api.dart';
import 'package:clashbot_flutter/core/config/env.dart';
import 'package:clashbot_flutter/globals/color_schemes.dart';
+import 'package:clashbot_flutter/models/clash_team.dart';
import 'package:clashbot_flutter/models/model_first_time.dart';
import 'package:clashbot_flutter/pages/home/page/home_v2.dart';
+import 'package:clashbot_flutter/pages/home/page/widgets/team_card.dart';
import 'package:clashbot_flutter/pages/intro/welcome_page.dart';
import 'package:clashbot_flutter/routes.dart';
import 'package:clashbot_flutter/services/clashbot_service.dart';
@@ -15,7 +17,10 @@ import 'package:clashbot_flutter/services/discord_service_mock_impl.dart';
import 'package:clashbot_flutter/services/riot_resources_service.dart';
import 'package:clashbot_flutter/services/riot_resources_service_impl.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
+import 'package:clashbot_flutter/stores/riot_champion.store.dart';
import 'package:clashbot_flutter/stores/v2-stores/clash.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/error_handler.store.dart';
import 'package:clashbot_flutter/styles.dart';
import 'package:clashbot_flutter/utils/reusable_widgets.dart';
import 'package:flutter/material.dart';
@@ -26,6 +31,7 @@ import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
import 'package:provider/provider.dart';
import 'package:validators/validators.dart';
+import 'package:storybook_flutter/storybook_flutter.dart';
import 'generated/git_info.dart';
import 'globals/global_settings.dart';
@@ -128,25 +134,33 @@ class _MyAppState extends State {
create: (_) => RiotResourceServiceImpl()),
Provider(
create: (_) => ClashBotEventsService()),
- ProxyProvider4(
- update: (_, discordService, clashBotService, riotResourceService,
- clashBotEventService, __) =>
- ApplicationDetailsStore(discordService, clashBotService,
- riotResourceService, clashBotEventService)),
- ProxyProvider2(
- update: (_, applicationDetailsStore, clashBotService, __) =>
- ClashStore(clashBotService, applicationDetailsStore))
+ Provider(create: (_) => ErrorHandlerStore()),
+ ProxyProvider2(
+ update: (_, clashBotService, errorHandlerStore, __) =>
+ ClashStore(clashBotService, errorHandlerStore)),
+ ProxyProvider2(
+ update: (_, discordService, errorHandlerStore, __) =>
+ DiscordDetailsStore(discordService, errorHandlerStore)),
+ ProxyProvider2(
+ update: (_, riotResourceService, errorHandlerStore, __) =>
+ RiotChampionStore(riotResourceService, errorHandlerStore)),
+ // Depends on ClashStore, DiscordDetailsStore, RiotChampionStore, ErrorHandlerStore
+ ProxyProvider4(
+ update: (_, clashStore, discordDetailsStore, riotChampionStore,
+ errorHandlerStore, __) =>
+ ApplicationDetailsStore(clashStore, discordDetailsStore,
+ riotChampionStore, errorHandlerStore)),
],
child: Consumer2(builder:
(context, ApplicationDetailsStore appStore,
ModelFirstTime modelFirstTime, child) {
- if (modelFirstTime.visited) {
- appStore.loadUserDetails();
+ if (modelFirstTime.visited && !appStore.isLoggedIn) {
+ appStore.refreshDiscordUser();
}
- return Observer(builder: (_) {
- return const MainApp();
- });
+ return const MainApp();
}));
}
}
@@ -270,28 +284,27 @@ class MainContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final appStore = context.read();
+ final discordDetailsStore = context.read();
+ final errorStore = context.read();
autorun((_) {
- if ('' != appStore.error) {
+ if ('' != errorStore.errorMessage) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
- backgroundColor: Colors.redAccent, content: Text(appStore.error)));
- appStore.error = '';
+ backgroundColor: Colors.redAccent,
+ content: Text(errorStore.errorMessage)));
+ errorStore.errorMessage = '';
}
- appStore.discordDetailsStore.discordIdToName.forEach((key, value) {
- developer.log("$key => $value");
- });
});
return Consumer(
builder: (context, ModelTheme themeNotifier, consChild) {
return Scaffold(
appBar: AppBar(title: const Text('ClashBot 2.0'), actions: [
- Observer(
- builder: (_) => Badge.count(
- count: appStore.unreadNotifications.length,
- alignment: AlignmentDirectional.bottomStart,
- isLabelVisible: appStore.unreadNotifications.isNotEmpty,
- child: const ClashBotNotificationsWidget(),
- )),
+ // Observer(
+ // builder: (_) => Badge.count(
+ // count: appStore.unreadNotifications.length,
+ // alignment: AlignmentDirectional.bottomStart,
+ // isLabelVisible: appStore.unreadNotifications.isNotEmpty,
+ // child: const ClashBotNotificationsWidget(),
+ // )),
Column(
mainAxisSize: MainAxisSize.min,
// spacing: 1.0,
@@ -322,11 +335,11 @@ class MainContainer extends StatelessWidget {
: themeNotifier.isDark = true;
}),
Observer(builder: (_) {
- if (appStore.isLoggedIn) {
+ if (discordDetailsStore.userHasLoggedIn) {
return PopupMenuButton(
icon: CircleAvatar(
- backgroundImage: NetworkImage(appStore
- .discordDetailsStore.discordUser.avatarURL))
+ backgroundImage: NetworkImage(
+ discordDetailsStore.discordUser.avatarURL))
.animate()
.shake(duration: const Duration(seconds: 1)),
offset: const Offset(0, 50),
@@ -354,39 +367,39 @@ class MainContainer extends StatelessWidget {
}
}
-class ClashBotNotificationsWidget extends StatelessWidget {
- const ClashBotNotificationsWidget({super.key});
+// class ClashBotNotificationsWidget extends StatelessWidget {
+// const ClashBotNotificationsWidget({super.key});
- @override
- Widget build(BuildContext context) {
- final appStore = context.read();
- return Observer(builder: (_) {
- return PopupMenuButton(
- icon: const Icon(Icons.add_alert),
- tooltip: 'Notifications',
- position: PopupMenuPosition.under,
- itemBuilder: (BuildContext context) {
- return appStore.sortedNotifications.map((notification) {
- var discordGuild = appStore
- .discordDetailsStore.discordGuildMap[notification.serverId];
- return PopupMenuItem(
- value: notification.uuid,
- enabled: !notification.read,
- padding: const EdgeInsets.all(2.0),
- child: ClashBotNotificationBody(
- serverName: discordGuild?.name ?? '',
- message: notification.message,
- causedBy: notification.causedBy,
- timestamp: notification.timestamp,
- iconUrl: discordGuild?.iconURL ?? '',
- ));
- }).toList();
- },
- onSelected: (value) => appStore.readNotification(value),
- );
- });
- }
-}
+// @override
+// Widget build(BuildContext context) {
+// final discordDetailsStore = context.read();
+// return Observer(builder: (_) {
+// return PopupMenuButton(
+// icon: const Icon(Icons.add_alert),
+// tooltip: 'Notifications',
+// position: PopupMenuPosition.under,
+// itemBuilder: (BuildContext context) {
+// return appStore.sortedNotifications.map((notification) {
+// var discordGuild = appStore
+// .discordDetailsStore.discordGuildMap[notification.serverId];
+// return PopupMenuItem(
+// value: notification.uuid,
+// enabled: !notification.read,
+// padding: const EdgeInsets.all(2.0),
+// child: ClashBotNotificationBody(
+// serverName: discordGuild?.name ?? '',
+// message: notification.message,
+// causedBy: notification.causedBy,
+// timestamp: notification.timestamp,
+// iconUrl: discordGuild?.iconURL ?? '',
+// ));
+// }).toList();
+// },
+// onSelected: (value) => appStore.readNotification(value),
+// );
+// });
+// }
+// }
class ClashBotNotificationBody extends StatelessWidget {
ClashBotNotificationBody({
@@ -474,6 +487,7 @@ class DrawerHeaderContentWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final applicationDetailsStore = context.read();
+ final discordDetailsStore = context.read();
return Column(
children: [
Observer(
@@ -482,13 +496,12 @@ class DrawerHeaderContentWidget extends StatelessWidget {
return Row(children: [
ListTile(
leading: CircleAvatar(
- backgroundImage: NetworkImage(applicationDetailsStore
- .discordDetailsStore.discordUser.avatarURL),
+ backgroundImage:
+ NetworkImage(discordDetailsStore.discordUser.avatarURL),
radius: 20,
),
title: Text(
- applicationDetailsStore
- .discordDetailsStore.discordUser.username,
+ discordDetailsStore.discordUser.username,
style: const TextStyle(
color: Colors.white,
fontSize: 24,
@@ -500,7 +513,7 @@ class DrawerHeaderContentWidget extends StatelessWidget {
children: [
ListTile(
leading: const Icon(Icons.discord),
- title: Text(applicationDetailsStore.id,
+ title: Text(discordDetailsStore.discordUser.id,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
diff --git a/lib/models/clashbot_user.dart b/lib/models/clashbot_user.dart
index a97ce82..a0dd9a6 100644
--- a/lib/models/clashbot_user.dart
+++ b/lib/models/clashbot_user.dart
@@ -46,4 +46,15 @@ class ClashBotUser {
/// The list of preferred Discord Servers for the player to filter by.
List preferredServers;
+
+ ClashBotUser copy() {
+ return ClashBotUser(
+ discordId: discordId,
+ role: role,
+ champions: champions,
+ subscriptions: subscriptions,
+ serverId: serverId,
+ selectedServers: selectedServers,
+ preferredServers: preferredServers);
+ }
}
diff --git a/lib/models/discord_user.dart b/lib/models/discord_user.dart
index 124bff4..a1bee53 100644
--- a/lib/models/discord_user.dart
+++ b/lib/models/discord_user.dart
@@ -24,7 +24,8 @@ class DiscordUser {
late String discriminator;
String get userDiscr => "$username#$discriminator";
- String get avatarURL => "${AppGlobalSettings.CND_DISCORD_AVATAR_URL}$id/$avatar.png";
+ String get avatarURL =>
+ "${AppGlobalSettings.CND_DISCORD_AVATAR_URL}$id/$avatar.png";
DiscordUser(
this.id,
@@ -90,4 +91,8 @@ class DiscordUser {
avatar.hashCode ^
discriminator.hashCode;
}
+
+ DiscordUser copy() {
+ return DiscordUser(id, username, avatar, discriminator);
+ }
}
diff --git a/lib/pages/home/page/home_v2.dart b/lib/pages/home/page/home_v2.dart
index 3afb802..4dfca58 100644
--- a/lib/pages/home/page/home_v2.dart
+++ b/lib/pages/home/page/home_v2.dart
@@ -6,18 +6,20 @@ import 'package:clashbot_flutter/models/discord_guild.dart';
import 'package:clashbot_flutter/pages/home/page/widgets/calendar_widget.dart';
import 'package:clashbot_flutter/pages/home/page/widgets/events_widget.dart';
import 'package:clashbot_flutter/pages/home/page/widgets/server_chip_list.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/stores/v2-stores/clash.store.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
+import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
-class Event {
+class HomeEvent {
final DateTime date;
final String title;
final String description;
final ClashTeam team;
- Event({
+ HomeEvent({
required this.date,
required this.title,
required this.description,
@@ -87,16 +89,75 @@ class _HomeV2State extends State {
@override
Widget build(BuildContext context) {
+ ClashStore clashStore = context.read();
+ DiscordDetailsStore discordDetailsStore =
+ context.read();
return Scaffold(
- appBar: AppBar(
- title: const Text('Clash Tournaments'),
+ body: LayoutBuilder(
+ builder: (context, constraints) {
+ if (constraints.maxWidth > 500) {
+ return Row(
+ children: [
+ Flexible(
+ flex: 1,
+ child: Flex(direction: Axis.vertical, children: [
+ const ServerChipList(),
+ CalendarWidget(
+ focusedDay: _focusedDay,
+ selectedDay: _selectedDay,
+ clashStore: clashStore,
+ discordDetailsStore: discordDetailsStore),
+ Expanded(
+ child: Card.filled(
+ color: Theme.of(context).brightness == Brightness.dark
+ ? Colors.blueGrey
+ : Colors.blueAccent,
+ margin: const EdgeInsets.all(16.0),
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: SvgPicture.asset(
+ 'svgs/ClashBot-HomePage.svg',
+ semanticsLabel: 'Clash Bot Home Page',
+ width: 100,
+ height: 600,
+ ),
+ ),
+ ),
+ ),
+ ]),
+ ),
+ const Flexible(
+ flex: 2,
+ child: EventsListWidget(),
+ ),
+ ],
+ );
+ } else {
+ return Column(
+ children: [
+ ServerChipList(),
+ CalendarWidget(
+ focusedDay: _focusedDay,
+ selectedDay: _selectedDay,
+ clashStore: clashStore,
+ discordDetailsStore: discordDetailsStore),
+ EventsListWidget(),
+ ],
+ );
+ }
+ },
),
- body: Column(
- children: [
- const ServerChipList(),
- CalendarWidget(focusedDay: _focusedDay, selectedDay: _selectedDay),
- Expanded(child: EventsListWidget()),
- ],
+ floatingActionButton: Observer(
+ builder: (_) => clashStore.canCreateTeam
+ ? FloatingActionButton(
+ onPressed: () {
+ ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
+ content: const Text('Creating team coming soon.'),
+ ));
+ },
+ child: const Icon(Icons.add),
+ )
+ : Container(),
),
);
}
diff --git a/lib/pages/home/page/widgets/calendar_widget.dart b/lib/pages/home/page/widgets/calendar_widget.dart
index 0de5e98..9619844 100644
--- a/lib/pages/home/page/widgets/calendar_widget.dart
+++ b/lib/pages/home/page/widgets/calendar_widget.dart
@@ -1,22 +1,29 @@
-import 'package:clashbot_flutter/models/clash_team.dart';
-import 'package:clashbot_flutter/models/clash_tournament.dart';
import 'package:clashbot_flutter/pages/home/page/home_v2.dart';
-import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/pages/shimmer_loading_page.dart';
import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/stores/v2-stores/clash.store.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart';
-import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
-import 'dart:developer' as developer;
+/// This widget requires the following providers:
+///
+/// - ClashStore
+/// - DiscordDetailsStore
class CalendarWidget extends StatefulWidget {
final DateTime focusedDay;
final DateTime? selectedDay;
+ // Define all required providers
+ final ClashStore clashStore;
+ final DiscordDetailsStore discordDetailsStore;
const CalendarWidget(
- {super.key, required this.focusedDay, required this.selectedDay});
+ {super.key,
+ required this.focusedDay,
+ required this.selectedDay,
+ required this.clashStore,
+ required this.discordDetailsStore});
@override
_CalendarWidgetState createState() => _CalendarWidgetState();
@@ -53,35 +60,82 @@ class _CalendarWidgetState extends State {
@override
Widget build(BuildContext context) {
bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
- ApplicationDetailsStore appStore = context.read();
- ClashStore clashStore = context.read();
- return SizedBox(
- width: 1000.0,
- child: Container(
- padding: const EdgeInsets.all(16.0),
- child: Column(
- children: [
- CalendarHeader(
- focusedDay: _focusedDay,
- onMonthChanged: onMonthChanged,
- ),
- CalendarBody(
- focusedDay: _focusedDay,
- hoveredDay: _hoveredDay,
- isDarkMode: isDarkMode,
- appStore: appStore,
- clashStore: clashStore,
- onDaySelected: onDaySelected,
- onHoveredDayChanged: (day) {
- setState(() {
- _hoveredDay = day;
- });
- },
- ),
- ],
- ),
- ),
- );
+ return Observer(
+ builder: (_) => widget.clashStore.isRefreshingData
+ ? SizedBox(
+ width: 1000.0, child: LoadingCalendar(focusedDay: _focusedDay))
+ : SizedBox(
+ width: 1000.0,
+ child: Container(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ CalendarHeader(
+ focusedDay: _focusedDay,
+ onMonthChanged: onMonthChanged,
+ ),
+ CalendarBody(
+ focusedDay: _focusedDay,
+ hoveredDay: _hoveredDay,
+ isDarkMode: isDarkMode,
+ discordDetailsStore: widget.discordDetailsStore,
+ clashStore: widget.clashStore,
+ onDaySelected: onDaySelected,
+ onHoveredDayChanged: (day) {
+ setState(() {
+ _hoveredDay = day;
+ });
+ },
+ ),
+ ],
+ ),
+ ),
+ ));
+ }
+}
+
+class LoadingCalendar extends StatelessWidget {
+ const LoadingCalendar({
+ super.key,
+ required DateTime focusedDay,
+ }) : _focusedDay = focusedDay;
+
+ final DateTime _focusedDay;
+
+ @override
+ Widget build(BuildContext context) {
+ return ShimmyShimmer(child: LayoutBuilder(builder: (context, constraints) {
+ return Column(
+ children: [
+ Center(
+ child: Container(
+ width: constraints.maxWidth < 500 ? 200.0 : 400.0,
+ height: 50.0,
+ child: Card(),
+ )),
+ GridView.builder(
+ shrinkWrap: true,
+ gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+ crossAxisCount: 7,
+ childAspectRatio: constraints.maxWidth < 500 ? 1.0 : 1.5,
+ ),
+ itemCount:
+ DateTime(_focusedDay.year, _focusedDay.month + 1, 0).day +
+ DateTime(_focusedDay.year, _focusedDay.month, 1).weekday -
+ 1,
+ itemBuilder: (context, index) {
+ return Container(
+ margin: EdgeInsets.all(4.0),
+ child: const SizedBox(
+ width: 20.0,
+ height: 20.0,
+ child: Card(),
+ ),
+ );
+ }),
+ ],
+ );
+ }));
}
}
@@ -125,7 +179,7 @@ class CalendarBody extends StatelessWidget {
final DateTime focusedDay;
final DateTime? hoveredDay;
final bool isDarkMode;
- final ApplicationDetailsStore appStore;
+ final DiscordDetailsStore discordDetailsStore;
final ClashStore clashStore;
final Function onDaySelected;
final ValueChanged onHoveredDayChanged;
@@ -135,7 +189,7 @@ class CalendarBody extends StatelessWidget {
required this.focusedDay,
required this.hoveredDay,
required this.isDarkMode,
- required this.appStore,
+ required this.discordDetailsStore,
required this.clashStore,
required this.onDaySelected,
required this.onHoveredDayChanged,
@@ -165,7 +219,7 @@ class CalendarBody extends StatelessWidget {
DateTime currentDay =
DateTime(focusedDay.year, focusedDay.month, day);
return Observer(builder: (_) {
- List dayEvents = clashStore.events
+ List dayEvents = clashStore.events
.where((event) => isSameDay(event.date, currentDay))
.toList();
return MouseRegion(
@@ -222,12 +276,18 @@ class CalendarBody extends StatelessWidget {
padding: const EdgeInsets.only(left: 2.0),
child: Observer(
builder: (_) => CircleAvatar(
- backgroundImage: NetworkImage(
- appStore
- .discordDetailsStore
- .discordGuildMap[event
- .team.serverId]!
- .iconURL),
+ backgroundImage: discordDetailsStore
+ .discordGuildMap[
+ event.team
+ .serverId] !=
+ null
+ ? NetworkImage(
+ discordDetailsStore
+ .discordGuildMap[
+ event.team
+ .serverId]!
+ .iconURL)
+ : null,
radius: 8.0,
)),
);
diff --git a/lib/pages/home/page/widgets/events_widget.dart b/lib/pages/home/page/widgets/events_widget.dart
index 8a20f46..6dfb9d1 100644
--- a/lib/pages/home/page/widgets/events_widget.dart
+++ b/lib/pages/home/page/widgets/events_widget.dart
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
-import 'dart:developer' as developer;
class EventsListWidget extends StatelessWidget {
const EventsListWidget({super.key});
@@ -17,7 +16,6 @@ class EventsListWidget extends StatelessWidget {
return Observer(builder: (_) {
var events =
clashStore.tournamentsToTeamsFilteredToADayIfActive.entries.toList();
- developer.log("Events: $events");
return SingleChildScrollView(
child: ListView.builder(
shrinkWrap: true,
diff --git a/lib/pages/home/page/widgets/server_chip_list.dart b/lib/pages/home/page/widgets/server_chip_list.dart
index c3e1aaf..8f025df 100644
--- a/lib/pages/home/page/widgets/server_chip_list.dart
+++ b/lib/pages/home/page/widgets/server_chip_list.dart
@@ -1,5 +1,6 @@
import 'package:clashbot_flutter/models/discord_guild.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/stores/v2-stores/clash.store.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -12,6 +13,8 @@ class ServerChipList extends StatelessWidget {
@override
Widget build(BuildContext context) {
ApplicationDetailsStore appStore = context.read();
+ DiscordDetailsStore discordDetailsStore =
+ context.read();
ClashStore clashStore = context.read();
return Padding(
padding: const EdgeInsets.all(8.0),
@@ -19,25 +22,39 @@ class ServerChipList extends StatelessWidget {
scrollDirection: Axis.horizontal,
child: Observer(
builder: (_) {
+ developer.log("Preferred servers: ${appStore.preferredServers}");
return Row(
children: appStore.preferredServers.map((serverId) {
bool isSelected = clashStore.selectedServers.contains(serverId);
- DiscordGuild discordGuild =
- appStore.discordDetailsStore.discordGuildMap[serverId]!;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: FilterChip(
avatar: CircleAvatar(
- backgroundImage: NetworkImage(discordGuild.iconURL),
+ backgroundImage: discordDetailsStore
+ .discordGuildMap[serverId]?.iconURL !=
+ null
+ ? NetworkImage(discordDetailsStore
+ .discordGuildMap[serverId]!.iconURL)
+ : null,
foregroundColor: isSelected ? Colors.white : Colors.black,
),
- label: Text(discordGuild.name ?? 'Unknown'),
+ label: Text(
+ discordDetailsStore.discordGuildMap[serverId]?.name ??
+ 'Unknown'),
selected: isSelected,
onSelected: (selected) {
if (selected) {
- clashStore.addSelectedServer(discordGuild.id);
+ clashStore.addSelectedServer(discordDetailsStore
+ .discordGuildMap[serverId] !=
+ null
+ ? discordDetailsStore.discordGuildMap[serverId]!.id
+ : "");
} else {
- clashStore.removeSelectedServer(discordGuild.id);
+ clashStore.removeSelectedServer(discordDetailsStore
+ .discordGuildMap[serverId] !=
+ null
+ ? discordDetailsStore.discordGuildMap[serverId]!.id
+ : "");
}
},
),
diff --git a/lib/pages/home/page/widgets/team_card.dart b/lib/pages/home/page/widgets/team_card.dart
index a1c2978..c457cd6 100644
--- a/lib/pages/home/page/widgets/team_card.dart
+++ b/lib/pages/home/page/widgets/team_card.dart
@@ -1,6 +1,5 @@
import 'package:clash_bot_api/api.dart';
import 'package:clashbot_flutter/models/clash_team.dart';
-import 'package:clashbot_flutter/pages/home/page/home_v2.dart';
import 'package:clashbot_flutter/snackbars/join_team_snackbar.dart';
import 'package:clashbot_flutter/snackbars/remove_team_snackbar.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
@@ -9,6 +8,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:provider/provider.dart';
+import 'dart:developer' as developer;
+
class TeamCard extends StatelessWidget {
TeamCard({
super.key,
@@ -28,6 +29,8 @@ class TeamCard extends StatelessWidget {
Widget build(BuildContext context) {
ApplicationDetailsStore applicationDetailsStore =
context.read();
+ DiscordDetailsStore discordDetailsStore =
+ context.read();
return Card(
surfaceTintColor: Theme.of(context).brightness == Brightness.dark
? const Color.fromARGB(
@@ -35,48 +38,53 @@ class TeamCard extends StatelessWidget {
: const Color.fromARGB(
255, 38, 0, 255), // Original color for light mode
child: ConstrainedBox(
- constraints: const BoxConstraints(maxWidth: 330),
+ constraints: const BoxConstraints(maxHeight: 325, maxWidth: 300),
child: Padding(
padding: const EdgeInsets.all(8.0),
- child: Column(
+ child: Flex(
+ direction: Axis.vertical,
+ spacing: 10,
children: [
- Row(
+ Flex(
+ direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Row(
- children: [
- Observer(builder: (_) {
- return CircleAvatar(
- backgroundImage: NetworkImage(applicationDetailsStore
- .discordDetailsStore
- .discordGuildMap[team.serverId]!
- .iconURL),
- );
- }),
- SizedBox(width: 5),
- Text(
- team.name.length > 20
- ? '${team.name.substring(0, 20)}...'
- : team.name,
- style: Theme.of(context).textTheme.titleLarge,
- ),
- ],
+ Observer(builder: (_) {
+ return CircleAvatar(
+ backgroundImage: discordDetailsStore
+ .discordGuildMap[team.serverId]?.iconURL !=
+ null
+ ? NetworkImage(discordDetailsStore
+ .discordGuildMap[team.serverId]!.iconURL)
+ : null,
+ );
+ }),
+ Text(
+ team.name.length > 20
+ ? '${team.name.substring(0, 20)}...'
+ : team.name,
+ style: Theme.of(context).textTheme.titleLarge,
),
+ const IconButton.filledTonal(
+ tooltip: 'Coming soon...',
+ icon: Icon(Icons.fullscreen),
+ onPressed: null)
],
),
- Column(
- children: [
- Flex(
- direction: Axis.vertical,
- spacing: 4,
- children: Role.values.map((role) {
- return RoleChip(
- image: roleToImage[role] ?? 'Unknown',
- role: role,
- player: team.members[role],
- teamId: team.id);
- }).toList())
- ],
+ Expanded(
+ child: Flex(
+ direction: Axis.vertical,
+ spacing: 4,
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: Role.values.map((role) {
+ return RoleChip(
+ image: roleToImage[role] ?? 'Unknown',
+ role: role,
+ player: team.members[role],
+ teamId: team.id,
+ isUser: team.members[role]?.id ==
+ applicationDetailsStore.clashBotUser.discordId);
+ }).toList()),
),
],
),
@@ -92,23 +100,84 @@ class RoleChip extends StatelessWidget {
required this.image,
required this.role,
this.player,
- required this.teamId});
+ required this.teamId,
+ required this.isUser});
final String image;
final Role role;
final PlayerDetails? player;
final String teamId;
+ final bool isUser;
@override
Widget build(BuildContext context) {
return player != null
- ? RoleFilledWidget(
- role: role, player: player, teamId: teamId, image: image)
+ ? (isUser
+ ? UsersFilledButton(
+ role: role, player: player, teamId: teamId, image: image)
+ : RoleFilledWidget(
+ role: role, player: player, teamId: teamId, image: image))
: UnfilledRoleWidget(
role: role, player: player, teamId: teamId, image: image);
}
}
+class UsersFilledButton extends StatelessWidget {
+ const UsersFilledButton({
+ super.key,
+ required this.role,
+ required this.player,
+ required this.teamId,
+ required this.image,
+ });
+
+ final Role role;
+ final PlayerDetails? player;
+ final String teamId;
+ final String image;
+
+ @override
+ Widget build(BuildContext context) {
+ return FilledButton.tonal(
+ onPressed: () {
+ ScaffoldMessenger.of(context).showSnackBar(
+ removeFromTeam(role, player!.id, player!.name, teamId));
+ },
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Theme.of(context).colorScheme.inversePrimary),
+ ),
+ child: Flex(
+ direction: Axis.horizontal,
+ spacing: 5,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Flexible(
+ flex: 1,
+ child: SizedBox(
+ width: 15,
+ height: 15,
+ child: Image(image: AssetImage(image))),
+ ),
+ Expanded(
+ flex: 3,
+ child: Center(
+ child: Text(
+ player?.name ?? 'Unknown',
+ style: const TextStyle(fontWeight: FontWeight.bold),
+ ),
+ ),
+ ),
+ Flexible(
+ flex: 1,
+ child: Container(
+ width: 20,
+ ))
+ ]),
+ );
+ }
+}
+
class UnfilledRoleWidget extends StatelessWidget {
const UnfilledRoleWidget({
super.key,
@@ -136,10 +205,7 @@ class UnfilledRoleWidget extends StatelessWidget {
padding: const EdgeInsets.all(4.0),
child: Row(spacing: 5, children: [
SizedBox(
- width: 15,
- height: 15,
- child: Image(image: AssetImage(image))),
- // Text(role.toString())
+ width: 15, height: 15, child: Image(image: AssetImage(image)))
]),
)),
);
@@ -162,23 +228,30 @@ class RoleFilledWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return FilledButton(
- onPressed: () {
- ScaffoldMessenger.of(context).showSnackBar(
- removeFromTeam(role, player!.id, player!.name, teamId));
- },
- child: SizedBox(
- width: 150,
- child: Padding(
- padding: const EdgeInsets.all(4.0),
- child: Row(spacing: 5, children: [
- SizedBox(
- width: 15,
- height: 15,
- child: Image(image: AssetImage(image))),
- Text(player?.name ?? 'Unknown')
- ]),
+ return Flex(
+ direction: Axis.horizontal,
+ spacing: 5,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Flexible(
+ flex: 1,
+ child: SizedBox(
+ width: 15, height: 15, child: Image(image: AssetImage(image))),
+ ),
+ Expanded(
+ flex: 3,
+ child: Center(
+ child: Text(
+ player?.name ?? 'Unknown',
+ style: const TextStyle(fontWeight: FontWeight.bold),
+ ),
+ ),
),
- ));
+ Flexible(
+ flex: 1,
+ child: Container(
+ width: 20,
+ ))
+ ]);
}
}
diff --git a/lib/pages/intro/step_pages/login_to_discord.dart b/lib/pages/intro/step_pages/login_to_discord.dart
index 7877548..45f922b 100644
--- a/lib/pages/intro/step_pages/login_to_discord.dart
+++ b/lib/pages/intro/step_pages/login_to_discord.dart
@@ -1,5 +1,6 @@
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/styles.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -16,27 +17,29 @@ class LoginToDiscordWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final appStore = context.read();
- var dispose =
- when((_) => appStore.discordDetailsStore.detailsLoaded == true, () {
+ final discordDetailsStore = context.read();
+ var dispose = when(
+ (_) =>
+ discordDetailsStore.userHasLoggedIn == true &&
+ discordDetailsStore.discordGuilds.isNotEmpty, () {
callback(true);
});
return Observer(builder: (_) {
- return !appStore.discordDetailsStore.detailsLoaded
+ return !discordDetailsStore.userHasLoggedIn
? const AskToLogin()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
- backgroundImage: NetworkImage(
- appStore.discordDetailsStore.discordUser.avatarURL),
+ backgroundImage:
+ NetworkImage(discordDetailsStore.discordUser.avatarURL),
radius: 50,
),
const SizedBox(height: 10),
AnimatedTextKit(
animatedTexts: [
TypewriterAnimatedText(
- 'Welcome ${appStore.discordDetailsStore.discordUser.username}!',
+ 'Welcome ${discordDetailsStore.discordUser.username}!',
textStyle: subHeaderStyle,
speed: const Duration(milliseconds: 150),
),
@@ -59,14 +62,14 @@ class AskToLogin extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final appStore = context.read();
+ final discordDetailsStore = context.read();
return Observer(builder: (_) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Lets log you in to Discord!", style: subHeaderStyle),
const SizedBox(height: 10),
- appStore.discordDetailsStore.status == "NOT_LOADED"
+ !discordDetailsStore.loadingData
? const LoginToDiscord()
: ElevatedButton.icon(
onPressed: null,
@@ -86,10 +89,10 @@ class LoginToDiscord extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, appStore, child) => ElevatedButton(
+ return Consumer(
+ builder: (context, discordDetailsStore, child) => ElevatedButton(
onPressed: () {
- appStore.discordDetailsStore.loadEverything();
+ discordDetailsStore.fetchCurrentUserDetails();
},
child: const Text("Login to Discord")));
}
diff --git a/lib/pages/intro/step_pages/select_servers.dart b/lib/pages/intro/step_pages/select_servers.dart
index 513ebe9..acfe651 100644
--- a/lib/pages/intro/step_pages/select_servers.dart
+++ b/lib/pages/intro/step_pages/select_servers.dart
@@ -1,7 +1,5 @@
-import 'dart:developer' as developer;
-
import 'package:clashbot_flutter/models/discord_guild.dart';
-import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/stores/short-lived/selected_server_form.store.dart';
import 'package:clashbot_flutter/styles.dart';
import 'package:flutter/material.dart';
@@ -20,13 +18,11 @@ class ServerFormWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final applicationDetailsStore = context.read();
- applicationDetailsStore.discordDetailsStore.loadEverything();
+ final discordDetailsStore = context.read();
return Observer(
builder: (_) => ServerFormContent(
- guilds: applicationDetailsStore.discordDetailsStore.discordGuilds,
- guildMap:
- applicationDetailsStore.discordDetailsStore.discordGuildMap,
+ guilds: discordDetailsStore.discordGuilds,
+ guildMap: discordDetailsStore.discordGuildMap,
selectedServerFormStore: selectedServerFormStore,
));
}
@@ -104,23 +100,12 @@ class _ServerChoiceChipState extends State {
onSelected: !widget.selectedServerFormStore.maxServersReached
? (bool selected) {
setState(() {
- developer.log("Selected: $selected");
- developer.log(
- "Max Servers Reached: ${widget.selectedServerFormStore.maxServersReached}");
- developer.log("widget.guild.id: ${widget.guild.id}");
- developer.log(
- "listOfSelectedServers: ${widget.selectedServerFormStore.listOfSelectedServers}");
- developer.log(
- "Does it contain? ${widget.selectedServerFormStore.listOfSelectedServers.contains(widget.guild.id)}");
if (selected &&
!widget.selectedServerFormStore.maxServersReached) {
- developer.log("Adding server to list ${widget.guild.id}...");
widget.selectedServerFormStore.addServer(widget.guild.id);
} else if (!selected &&
widget.selectedServerFormStore.listOfSelectedServers
.contains(widget.guild.id)) {
- developer
- .log("Removing server from list ${widget.guild.id}...");
widget.selectedServerFormStore.removeServer(widget.guild.id);
}
});
diff --git a/lib/pages/intro/welcome_page.dart b/lib/pages/intro/welcome_page.dart
index 83759eb..3c9b900 100644
--- a/lib/pages/intro/welcome_page.dart
+++ b/lib/pages/intro/welcome_page.dart
@@ -7,6 +7,7 @@ import 'package:clashbot_flutter/pages/intro/step_pages/select_servers.dart';
import 'package:clashbot_flutter/pages/intro/step_pages/welcome.dart';
import 'package:clashbot_flutter/pages/intro/step_pages/what_is_clash.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/stores/short-lived/selected_server_form.store.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -131,10 +132,13 @@ class EndWelcomePageSessionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer2(builder: (context,
- ModelFirstTime modelFirstTime,
- ApplicationDetailsStore appStore,
- consChild) {
+ return Consumer3(
+ builder: (context,
+ ModelFirstTime modelFirstTime,
+ ApplicationDetailsStore appStore,
+ DiscordDetailsStore discordDetailsStore,
+ consChild) {
return Observer(builder: (context) {
return ElevatedButton.icon(
onPressed: !selectedServerFormStore.ableToSubmit
@@ -142,13 +146,11 @@ class EndWelcomePageSessionButton extends StatelessWidget {
: () {
selectedServerFormStore.submittingForm();
appStore
- .createUser(
- selectedServerFormStore.listOfSelectedServers.first
- .toString(),
+ .createUser(discordDetailsStore.discordUser.id,
selectedServerFormStore.listOfSelectedServers)
.then((value) {
modelFirstTime.visited = true;
- context.goNamed('teams');
+ context.goNamed('home');
}).catchError((error) {
selectedServerFormStore.callFailed = true;
selectedServerFormStore.submitting = false;
diff --git a/lib/services/clashbot_events_service.dart b/lib/services/clashbot_events_service.dart
index 4a6ad32..99fd16b 100644
--- a/lib/services/clashbot_events_service.dart
+++ b/lib/services/clashbot_events_service.dart
@@ -25,12 +25,8 @@ class ClashBotEventsService {
onConnect: (p0) => onConnect(),
connectionTimeout: const Duration(seconds: 20),
beforeConnect: () async {
- developer.log('waiting to connect...');
await Future.delayed(Duration(milliseconds: 200));
- developer.log('connecting...');
},
- onDebugMessage: (p0) => developer.log("Debug $p0"),
- onStompError: (p0) => developer.log("Error $p0"),
onWebSocketError: (error) => onError(error),
),
);
@@ -40,7 +36,6 @@ class ClashBotEventsService {
void setupSubscription(String loggedInUserId, String serverId,
Function notifyUser, DiscordDetailsStore detailsStore) {
- developer.log("Subscribing to $serverId...");
if (null != stompClient && stompClient!.connected) {
openConnections.putIfAbsent(
serverId,
@@ -48,7 +43,6 @@ class ClashBotEventsService {
destination: '/topic/server/$serverId',
callback: (frame) {
Event? result = Event.fromJson(json.decode(frame.body!));
- developer.log("Event recieved $result");
var discordId = result?.causedBy ?? '';
var username = detailsStore.discordIdToName[discordId];
if (isNull(username)) {
@@ -57,7 +51,6 @@ class ClashBotEventsService {
}
switch (result!.teamEvent.eventType) {
case EventType.CREATED:
- developer.log("${result.teamEvent.eventType} triggered.");
String message = '';
if (null != result.teamEvent.team) {
// clashPlayerStore.updateClashTeam(
@@ -106,7 +99,6 @@ class ClashBotEventsService {
DateTime.now()));
break;
case EventType.JOINED:
- developer.log("${result.teamEvent.eventType} triggered.");
String message = '';
if (null != result.teamEvent.team) {
// clashPlayerStore.updateClashTeam(
@@ -131,7 +123,6 @@ class ClashBotEventsService {
DateTime.now()));
break;
case EventType.REMOVED:
- developer.log("${result.teamEvent.eventType} triggered.");
String message = '';
if (null != result.teamEvent.team) {
// clashPlayerStore.updateClashTeam(
@@ -156,7 +147,6 @@ class ClashBotEventsService {
DateTime.now()));
break;
case EventType.DELETED:
- developer.log("Delete Event triggered.");
String message = '';
if (null != result.teamEvent.team) {
// clashPlayerStore.removeClashTeams(
@@ -180,7 +170,6 @@ class ClashBotEventsService {
DateTime.now()));
break;
default:
- developer.log("Unknown event type occurred.");
throw Error(message: "Unknown event type occurred.");
}
}));
@@ -191,7 +180,6 @@ class ClashBotEventsService {
var unsubscribe = openConnections[serverId];
if (null != unsubscribe) {
unsubscribe(unsubscribeHeaders: {});
- developer.log("Unsubscribed from $serverId.");
openConnections.remove(serverId);
}
}
diff --git a/lib/services/discord_service_impl.dart b/lib/services/discord_service_impl.dart
index 80c3704..de560fd 100644
--- a/lib/services/discord_service_impl.dart
+++ b/lib/services/discord_service_impl.dart
@@ -21,43 +21,48 @@ class DiscordServiceImpl implements DiscordService {
@override
Future fetchCurrentUserDetails() {
return retry(
- () => oAuth2Helper
- .get(
- AppGlobalSettings.apiEndpointURL +
- AppGlobalSettings.API_DISCORD_GET_CURRENT_USER,
- headers: baseHeaders)
- .then((response) {
- if (response.statusCode != 200) {
- throw ApiException(response.statusCode, response.reasonPhrase);
- }
- return response;
- }).timeout(const Duration(seconds: 5)),
- retryIf: (e) =>
- e is SocketException ||
- e is TimeoutException ||
- (e is ApiException && e.code == HttpStatus.tooManyRequests)).then(
- (value) => DiscordUser.fromJson(value.body));
+ () => oAuth2Helper
+ .get(
+ AppGlobalSettings.apiEndpointURL +
+ AppGlobalSettings.API_DISCORD_GET_CURRENT_USER,
+ headers: baseHeaders)
+ .then((response) {
+ if (response.statusCode != 200) {
+ throw ApiException(
+ response.statusCode, response.reasonPhrase);
+ }
+ return response;
+ }).timeout(const Duration(seconds: 5)),
+ retryIf: (e) =>
+ e is SocketException ||
+ e is TimeoutException ||
+ (e is ApiException && e.code == HttpStatus.tooManyRequests),
+ delayFactor: const Duration(seconds: 2))
+ .then((value) => DiscordUser.fromJson(value.body));
}
@override
Future> fetchUserGuilds() {
return retry(
- () => oAuth2Helper
- .get(
- AppGlobalSettings.apiEndpointURL +
- AppGlobalSettings.API_DISCORD_GET_CURRENT_USER_GUILDS,
- headers: baseHeaders)
- .then((response) {
- if (response.statusCode != 200) {
- throw ApiException(response.statusCode, response.reasonPhrase);
- }
- return response;
- }).timeout(const Duration(seconds: 5)),
- retryIf: (e) =>
- e is SocketException ||
- e is TimeoutException ||
- (e is ApiException && e.code == HttpStatus.tooManyRequests)).then(
- (value) {
+ () => oAuth2Helper
+ .get(
+ AppGlobalSettings.apiEndpointURL +
+ AppGlobalSettings
+ .API_DISCORD_GET_CURRENT_USER_GUILDS,
+ headers: baseHeaders)
+ .then((response) {
+ if (response.statusCode != 200) {
+ throw ApiException(
+ response.statusCode, response.reasonPhrase);
+ }
+ return response;
+ }).timeout(const Duration(seconds: 5)),
+ retryIf: (e) =>
+ e is SocketException ||
+ e is TimeoutException ||
+ (e is ApiException && e.code == HttpStatus.tooManyRequests),
+ delayFactor: const Duration(seconds: 2))
+ .then((value) {
Iterable l = jsonDecode(value.body);
return List.from(l.map((model) {
return DiscordGuild.fromMap(model);
@@ -73,22 +78,24 @@ class DiscordServiceImpl implements DiscordService {
@override
Future fetchUserDetails(String discordId) {
return retry(
- () => oAuth2Helper
- .get(
- AppGlobalSettings.apiEndpointURL +
- AppGlobalSettings.API_DISCORD_GET_USER +
- discordId,
- headers: baseHeaders)
- .then((response) {
- if (response.statusCode != 200) {
- throw ApiException(response.statusCode, response.reasonPhrase);
- }
- return response;
- }).timeout(const Duration(seconds: 5)),
- retryIf: (e) =>
- e is SocketException ||
- e is TimeoutException ||
- (e is ApiException && e.code == HttpStatus.tooManyRequests)).then(
- (value) => DiscordUser.fromJson(value.body));
+ () => oAuth2Helper
+ .get(
+ AppGlobalSettings.apiEndpointURL +
+ AppGlobalSettings.API_DISCORD_GET_USER +
+ discordId,
+ headers: baseHeaders)
+ .then((response) {
+ if (response.statusCode != 200) {
+ throw ApiException(
+ response.statusCode, response.reasonPhrase);
+ }
+ return response;
+ }).timeout(const Duration(seconds: 5)),
+ retryIf: (e) =>
+ e is SocketException ||
+ e is TimeoutException ||
+ (e is ApiException && e.code == HttpStatus.tooManyRequests),
+ delayFactor: const Duration(seconds: 2))
+ .then((value) => DiscordUser.fromJson(value.body));
}
}
diff --git a/lib/stores/application_details.store.dart b/lib/stores/application_details.store.dart
index ea05840..e41e3ab 100644
--- a/lib/stores/application_details.store.dart
+++ b/lib/stores/application_details.store.dart
@@ -1,64 +1,56 @@
-import 'dart:convert';
-import 'dart:math';
-
import 'package:clash_bot_api/api.dart';
-import 'package:clashbot_flutter/globals/global_settings.dart';
import 'package:clashbot_flutter/models/clash_notification.dart';
-import 'package:clashbot_flutter/models/clash_tournament.dart';
import 'package:clashbot_flutter/models/clashbot_user.dart';
-import 'package:clashbot_flutter/models/discord_guild.dart';
-import 'package:clashbot_flutter/models/discord_user.dart';
-import 'package:clashbot_flutter/models/model_first_time.dart';
-import 'package:clashbot_flutter/services/clashbot_events_service.dart';
import 'package:clashbot_flutter/services/clashbot_service.dart';
-import 'package:clashbot_flutter/services/discord_service.dart';
-import 'package:clashbot_flutter/services/riot_resources_service.dart';
import 'package:clashbot_flutter/stores/discord_details.store.dart';
import 'package:clashbot_flutter/stores/riot_champion.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/clash.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/error_handler.store.dart';
import 'package:collection/collection.dart';
-import 'package:flutter/widgets.dart';
-import 'package:http/http.dart';
import 'package:mobx/mobx.dart';
-import 'package:oauth2_client/oauth2_helper.dart';
-import 'package:shared_preferences/shared_preferences.dart';
import 'dart:developer' as developer;
part 'application_details.store.g.dart';
-class ApplicationDetailsStore extends _ApplicationDetailsStore
- with _$ApplicationDetailsStore {
- ApplicationDetailsStore(
- DiscordService discordService,
- ClashBotService clashBotService,
- RiotResourcesService riotResourcesService,
- ClashBotEventsService clashBotEventsService)
- : super(discordService, clashBotService, riotResourcesService,
- clashBotEventsService) {
- discordDetailsStore = DiscordDetailsStore(_discordService, this);
- riotChampionStore = RiotChampionStore(_riotResourcesService, this);
- }
-}
+class ApplicationDetailsStore = _ApplicationDetailsStore
+ with _$ApplicationDetailsStore;
abstract class _ApplicationDetailsStore with Store {
- late DiscordDetailsStore discordDetailsStore;
- final DiscordService _discordService;
- final ClashBotService _clashBotService;
- late RiotChampionStore riotChampionStore;
- final RiotResourcesService _riotResourcesService;
- final ClashBotEventsService _clashBotEventsService;
- _ApplicationDetailsStore(this._discordService, this._clashBotService,
- this._riotResourcesService, this._clashBotEventsService) {
- reaction((_) => id, (_) {
- refreshClashBotUser();
- refreshSelectedServers();
+ late DiscordDetailsStore _discordDetailsStore;
+ late RiotChampionStore _riotChampionStore;
+ final ClashStore _clashStore;
+ final ErrorHandlerStore _errorHandlerStore;
+ _ApplicationDetailsStore(this._clashStore, this._discordDetailsStore,
+ this._riotChampionStore, this._errorHandlerStore) {
+ reaction((_) => _discordDetailsStore.discordUser, (_) {
+ developer.log("reaction: _discordDetailsStore.discordUser");
+ if (_discordDetailsStore.discordUser.id != '0') {
+ developer.log("Refreshing clash bot user");
+ _clashStore.refreshClashBotUser(_discordDetailsStore.discordUser.id);
+ _clashStore.refreshSelectedServers();
+ _discordDetailsStore.fetchUserGuilds();
+ }
+ });
+ reaction((_) => _clashStore.clashBotUser, (_) {
+ if (_clashStore.clashBotUser.discordId != '0' &&
+ !_clashStore.refreshingUser) {
+ _clashStore
+ .refreshClashTournaments(_clashStore.clashBotUser.discordId!);
+ _clashStore.refreshClashTeams(_clashStore.clashBotUser.discordId!,
+ _clashStore.clashBotUser.selectedServers);
+ }
});
}
@observable
- String id = '0';
+ ClashBotUser clashBotUser = ClashBotUser();
@observable
- ClashBotUser clashBotUser = ClashBotUser();
+ ObservableList notifications = ObservableList();
+
+ @computed
+ bool get isLoggedIn =>
+ _discordDetailsStore.userHasLoggedIn && clashBotUser.discordId != '0';
// Create map of String to subscription
@computed
@@ -69,32 +61,13 @@ abstract class _ApplicationDetailsStore with Store {
value: (e) => e as Subscription,
));
- @observable
- ObservableList preferredServers = ObservableList();
-
@computed
ObservableList get sortedSelectedServers =>
ObservableList.of(clashBotUser.selectedServers.sorted());
- @action
- Future refreshSelectedServers() async {
- preferredServers.clear();
- var userDetails = await _clashBotService.getPlayer(id);
- developer.log(userDetails.selectedServers.toString());
- preferredServers = ObservableList.of(userDetails.selectedServers);
- developer.log("Preferred: " + preferredServers.toString());
- }
-
- @action
- Future refreshClashBotUser() async {
- clashBotUser = await _clashBotService.getPlayer(id);
- }
-
- @observable
- String error = '';
-
- @observable
- ObservableList notifications = ObservableList();
+ @computed
+ ObservableList get preferredServers =>
+ ObservableList.of(_clashStore.selectedServers);
@computed
List get sortedNotifications =>
@@ -104,13 +77,9 @@ abstract class _ApplicationDetailsStore with Store {
List get unreadNotifications =>
notifications.where((notification) => !notification.read).toList();
- @computed
- bool get isLoggedIn =>
- discordDetailsStore.detailsLoaded && clashBotUser.discordId != '0';
-
@action
- void triggerError(String errorMessage) {
- error = errorMessage;
+ void refreshDiscordUser() {
+ _discordDetailsStore.fetchCurrentUserDetails();
}
@action
@@ -139,42 +108,15 @@ abstract class _ApplicationDetailsStore with Store {
}
@action
- Future loadUserDetails() async {
- try {
- await Future.wait([
- discordDetailsStore.loadEverything(),
- riotChampionStore.refreshChampionData()
- ]);
- // _clashBotEventsService.connectClient(() {
- // for (var serverId in loggedInClashUser.preferredServers) {
- // _clashBotEventsService.setupSubscription(
- // id, serverId, notifyUser, loggedInClashUser, discordDetailsStore);
- // }
- // }, (dynamic error) {
- // developer.log("Websocket connection failure.", error: error);
- // error = "Failed to connect to Server events.";
- // });
- } catch (error) {
- developer.log("Failed to load user.", error: error);
- this.error = 'Failed to load :(, please try again later.';
- }
- }
-
- @action
- Future createUser(
- String defaultServerId, List selectedServersToUse) async {
+ Future createUser(String id, List preferredServers) async {
try {
- clashBotUser = await _clashBotService.createPlayer(
- id, discordDetailsStore.discordUser.username, defaultServerId);
- var updatedSelectedServers = await _clashBotService.createSelectedServers(
- id, selectedServersToUse);
- clashBotUser.selectedServers = updatedSelectedServers;
- preferredServers.clear();
- preferredServers.addAll(updatedSelectedServers);
- return clashBotUser;
+ _clashStore.createPlayer(id, _discordDetailsStore.discordUser.username,
+ preferredServers.first);
+ _clashStore.createSelectedServers(id, preferredServers);
+ _clashStore.refreshClashBotUser(id);
} on Exception catch (issue) {
- error = 'Failed to create new Clash Bot User, please try again.';
- developer.log('Failed to create new Clash Bot User', error: issue);
+ _errorHandlerStore.errorMessage =
+ 'Failed to create new Clash Bot User, please try again.';
rethrow;
}
}
diff --git a/lib/stores/discord_details.store.dart b/lib/stores/discord_details.store.dart
index f712732..434f75a 100644
--- a/lib/stores/discord_details.store.dart
+++ b/lib/stores/discord_details.store.dart
@@ -3,24 +3,17 @@ import 'dart:async';
import 'package:clashbot_flutter/models/discord_guild.dart';
import 'package:clashbot_flutter/models/discord_user.dart';
import 'package:clashbot_flutter/services/discord_service.dart';
+import 'package:clashbot_flutter/stores/v2-stores/error_handler.store.dart';
import 'package:mobx/mobx.dart';
-import 'application_details.store.dart';
part 'discord_details.store.g.dart';
class DiscordDetailsStore = _DiscordDetailsStore with _$DiscordDetailsStore;
abstract class _DiscordDetailsStore with Store {
final DiscordService _discordService;
- final ApplicationDetailsStore _applicationDetailsStore;
- _DiscordDetailsStore(this._discordService, this._applicationDetailsStore) {
- reaction(
- (_) =>
- _applicationDetailsStore.id != '0' ||
- _applicationDetailsStore.id.isNotEmpty, (_) {
- loadEverything();
- });
- }
+ final ErrorHandlerStore _errorHandlerStore;
+ _DiscordDetailsStore(this._discordService, this._errorHandlerStore);
@observable
DiscordUser discordUser = DiscordUser('0', 'Not Logged In', 'N/A', '');
@@ -32,10 +25,13 @@ abstract class _DiscordDetailsStore with Store {
ObservableMap discordIdToName = ObservableMap();
@observable
- String status = 'NOT_LOADED';
+ ObservableList callsInProgress = ObservableList();
+
+ @computed
+ bool get loadingData => callsInProgress.isNotEmpty;
@computed
- bool get detailsLoaded => discordUser.id != '0';
+ bool get userHasLoggedIn => discordUser.id != '0';
@computed
bool get guildDetailsLoaded => discordGuildMap.isNotEmpty;
@@ -45,60 +41,45 @@ abstract class _DiscordDetailsStore with Store {
{for (var guild in discordGuilds) guild.id: guild};
@action
- Future fetchUserDetails(String discordId) async {
+ Future fetchUserDetails(String discordId) async {
+ callsInProgress.add('fetchUserDetails');
var foundUser;
try {
foundUser = await _discordService.fetchUserDetails(discordId);
discordIdToName.putIfAbsent(discordId, () => foundUser.username);
- } on Exception catch (error) {}
- return foundUser;
+ } on Exception catch (error) {
+ _errorHandlerStore.errorMessage =
+ 'Failed to fetch Discord User details due to ${error.toString()}';
+ }
+ callsInProgress.remove('fetchUserDetails');
}
@action
Future fetchCurrentUserDetails() async {
- status = 'LOADING';
+ callsInProgress.add('fetchCurrentUserDetails');
final future = _discordService.fetchCurrentUserDetails();
try {
DiscordUser updatedUser = await future;
- discordUser = updatedUser;
- _applicationDetailsStore.id = discordUser.id;
+ discordUser = updatedUser.copy();
discordIdToName.putIfAbsent(updatedUser.id, () => updatedUser.username);
- status = 'LOADED';
} on Exception catch (error) {
- _applicationDetailsStore.error =
+ _errorHandlerStore.errorMessage =
'Failed to fetch Discord User details due to ${error.toString()}';
- status = 'NOT LOADED';
}
+ callsInProgress.remove('fetchCurrentUserDetails');
}
@action
Future fetchUserGuilds() async {
- status = 'LOADING';
+ callsInProgress.add('fetchUserGuilds');
final future = _discordService.fetchUserGuilds();
try {
List guilds = await future;
discordGuilds.clear();
discordGuilds.addAll(guilds);
- status = 'LOADED';
- } on Exception catch (error) {
- _applicationDetailsStore.error = error.toString();
- status = 'NOT LOADED';
- }
- }
-
- @action
- Future loadEverything() async {
- status = 'LOADING';
- try {
- // await _discordService.loginToDiscord();
- await Future.wait([fetchCurrentUserDetails(), fetchUserGuilds()]);
-
- _applicationDetailsStore.id = discordUser.id;
-
- status = 'LOADED';
} on Exception catch (error) {
- _applicationDetailsStore.error = error.toString();
- status = 'NOT LOADED';
+ _errorHandlerStore.errorMessage = error.toString();
}
+ callsInProgress.remove('fetchUserGuilds');
}
}
diff --git a/lib/stores/discordoauth2.store.dart b/lib/stores/discordoauth2.store.dart
index d3a541a..cce3731 100644
--- a/lib/stores/discordoauth2.store.dart
+++ b/lib/stores/discordoauth2.store.dart
@@ -19,10 +19,9 @@ part 'discordoauth2.store.g.dart';
class DiscordOAuth2Store = _DiscordOAuth2Store with _$DiscordOAuth2Store;
abstract class _DiscordOAuth2Store with Store {
-
@observable
DiscordUser currentUser = new DiscordUser('0', 'Not Logged In', 'N/A', '');
-
+
@observable
List usersGuilds = [];
@@ -42,46 +41,50 @@ abstract class _DiscordOAuth2Store with Store {
@action
void setOAuth2Helper(OAuth2Helper oAuth2Helper) {
- developer.log("SettingOAuth2Helper...");
this.oAuth2Helper = oAuth2Helper;
}
@observable
- ObservableFuture discordUserFuture = ObservableFuture.value(new DiscordUser('0', 'Not Logged In', 'N/A', ''));
+ ObservableFuture discordUserFuture =
+ ObservableFuture.value(new DiscordUser('0', 'Not Logged In', 'N/A', ''));
@observable
- ObservableFuture> discordGuildsFuture = ObservableFuture.value([]);
+ ObservableFuture> discordGuildsFuture =
+ ObservableFuture.value([]);
@computed
bool get userDetailsReady =>
- discordUserFuture != ObservableFuture.value(new DiscordUser('0', 'Not Logged In', 'N/A', '')) &&
+ discordUserFuture !=
+ ObservableFuture.value(
+ new DiscordUser('0', 'Not Logged In', 'N/A', '')) &&
discordUserFuture.status == FutureStatus.fulfilled;
@action
Future fetchCurrentUserDetails() async {
final future = oAuth2Helper?.get(
- AppGlobalSettings.apiEndpointURL + AppGlobalSettings.API_DISCORD_GET_CURRENT_USER,
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded'
- }
- ).then((value) => DiscordUser.fromJson(value.body));
+ AppGlobalSettings.apiEndpointURL +
+ AppGlobalSettings.API_DISCORD_GET_CURRENT_USER,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ }).then((value) => DiscordUser.fromJson(value.body));
if (future != null) {
discordUserFuture = ObservableFuture(future);
return currentUser = await future;
}
- return ObservableFuture.value(new DiscordUser('0', 'Not Logged In', 'N/A', ''));
+ return ObservableFuture.value(
+ new DiscordUser('0', 'Not Logged In', 'N/A', ''));
}
@action
Future> fetchUserGuilds() async {
final future = oAuth2Helper?.get(
- AppGlobalSettings.apiEndpointURL + AppGlobalSettings.API_DISCORD_GET_CURRENT_USER_GUILDS,
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded'
- }
- ).then((value) {
+ AppGlobalSettings.apiEndpointURL +
+ AppGlobalSettings.API_DISCORD_GET_CURRENT_USER_GUILDS,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ }).then((value) {
Iterable l = jsonDecode(value.body);
return List.from(l.map((model) {
return DiscordGuild.fromMap(model);
@@ -121,4 +124,4 @@ abstract class _DiscordOAuth2Store with Store {
void setUserOAuth2ReponseURL(String url) {
userOAuth2ReponseURL = url;
}
-}
\ No newline at end of file
+}
diff --git a/lib/stores/riot_champion.store.dart b/lib/stores/riot_champion.store.dart
index 0a3c69b..bcef7c3 100644
--- a/lib/stores/riot_champion.store.dart
+++ b/lib/stores/riot_champion.store.dart
@@ -1,25 +1,16 @@
import 'package:clashbot_flutter/models/lol_champion.dart';
import 'package:clashbot_flutter/services/riot_resources_service.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/error_handler.store.dart';
import 'package:mobx/mobx.dart';
part 'riot_champion.store.g.dart';
-class RiotChampionStore extends _RiotChampionStoreBase
- with _$RiotChampionStore {
- RiotChampionStore(RiotResourcesService riotResourcesService,
- ApplicationDetailsStore applicationDetailsStore)
- : super(riotResourcesService, applicationDetailsStore);
-}
+class RiotChampionStore = _RiotChampionStore with _$RiotChampionStore;
-abstract class _RiotChampionStoreBase with Store {
- ApplicationDetailsStore _applicationDetailsStore;
+abstract class _RiotChampionStore with Store {
RiotResourcesService _riotResourcesService;
- _RiotChampionStoreBase(
- this._riotResourcesService, this._applicationDetailsStore) {
- reaction((_) => _applicationDetailsStore.id, (_) {
- refreshChampionData();
- });
- }
+ ErrorHandlerStore _errorHandlerStore;
+ _RiotChampionStore(this._riotResourcesService, this._errorHandlerStore);
@observable
LoLChampionsData lChampionsData = LoLChampionsData();
diff --git a/lib/stores/v2-stores/clash.store.dart b/lib/stores/v2-stores/clash.store.dart
index dda0800..fd1b961 100644
--- a/lib/stores/v2-stores/clash.store.dart
+++ b/lib/stores/v2-stores/clash.store.dart
@@ -1,11 +1,11 @@
+import 'package:clash_bot_api/api.dart';
import 'package:clashbot_flutter/models/clash_team.dart';
import 'package:clashbot_flutter/models/clash_tournament.dart';
-import 'package:clashbot_flutter/models/discord_guild.dart';
-import 'package:clashbot_flutter/models/user.dart';
+import 'package:clashbot_flutter/models/clashbot_user.dart';
import 'package:clashbot_flutter/pages/home/page/home_v2.dart';
import 'package:clashbot_flutter/services/clashbot_service.dart';
import 'package:clashbot_flutter/stores/application_details.store.dart';
-import 'package:clashbot_flutter/stores/discord_details.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/error_handler.store.dart';
import 'package:mobx/mobx.dart';
import 'dart:developer' as developer;
@@ -17,25 +17,73 @@ class ClashStore = _ClashStore with _$ClashStore;
abstract class _ClashStore with Store {
final ClashBotService _clashService;
- final ApplicationDetailsStore _applicationDetailsStore;
+ final ErrorHandlerStore _errorhandlerStore;
- _ClashStore(this._clashService, this._applicationDetailsStore) {
- reaction((_) => _applicationDetailsStore.id, (_) {
- refreshClashTournaments();
- });
- reaction((_) => _applicationDetailsStore.preferredServers, (_) {
- resetSelectedServers();
- refreshClashTeams();
- });
- }
+ _ClashStore(this._clashService, this._errorhandlerStore);
+
+ // Constants for network calls
+ static const String refreshClashBotUserCall = "refreshClashBotUser";
+ static const String refreshClashTournamentsCall = "refreshClashTournaments";
+ static const String refreshClashTeamsCall = "refreshClashTeams";
+
+ @observable
+ ClashBotUser clashBotUser = ClashBotUser();
@observable
ObservableList selectedServers = ObservableList();
+ @observable
+ bool filterByDay = false;
+
+ @observable
+ DateTime filterDate = DateTime.now();
+
+ @observable
+ ObservableList tournaments = ObservableList();
+
+ @observable
+ ObservableList clashTeams = ObservableList();
+
+ @observable
+ bool refreshingUser = false;
+
+ @observable
+ ObservableList callsInProgress = ObservableList();
+
+ @computed
+ bool get isRefreshingData =>
+ callsInProgress.contains(_ClashStore.refreshClashBotUserCall) ||
+ callsInProgress.contains(_ClashStore.refreshClashTournamentsCall) ||
+ callsInProgress.contains(_ClashStore.refreshClashTeamsCall);
+
+ @action
+ void addCallInProgress(String call) {
+ callsInProgress.add(call);
+ }
+
+ @action
+ void removeCallInProgress(String call) {
+ callsInProgress.remove(call);
+ }
+
@action
- void resetSelectedServers() {
- selectedServers =
- ObservableList.of(_applicationDetailsStore.preferredServers);
+ void clearCallsInProgress() {
+ callsInProgress.clear();
+ }
+
+ @action
+ Future refreshClashBotUser(String id) async {
+ refreshingUser = true;
+ callsInProgress.add(_ClashStore.refreshClashBotUserCall);
+ clashBotUser = await _clashService.getPlayer(id);
+ setSelectedServer(clashBotUser.selectedServers);
+ callsInProgress.remove(_ClashStore.refreshClashBotUserCall);
+ refreshingUser = false;
+ }
+
+ @action
+ void refreshSelectedServers() {
+ selectedServers = ObservableList.of(clashBotUser.selectedServers);
}
@action
@@ -45,10 +93,7 @@ abstract class _ClashStore with Store {
@action
void addSelectedServer(String server) {
- if (_applicationDetailsStore.preferredServers.contains(server) &&
- !selectedServers.contains(server)) {
- selectedServers.add(server);
- }
+ selectedServers.add(server);
}
@action
@@ -56,8 +101,8 @@ abstract class _ClashStore with Store {
selectedServers.remove(server);
}
- @observable
- bool filterByDay = false;
+ @computed
+ bool get canCreateTeam => filterByDay;
@action
void turnOnDayFilter() {
@@ -69,17 +114,11 @@ abstract class _ClashStore with Store {
filterByDay = false;
}
- @observable
- DateTime filterDate = DateTime.now();
-
@action
void setFilterDate(DateTime date) {
filterDate = date;
}
- @observable
- ObservableList tournaments = ObservableList();
-
@computed
Map> get tournamentsByNameAndDay {
Map> tournamentsByNameAndDay = {};
@@ -94,9 +133,6 @@ abstract class _ClashStore with Store {
return tournamentsByNameAndDay;
}
- @observable
- ObservableList clashTeams = ObservableList();
-
@computed
Map> get tournamentsToTeams {
Map> tournamentsToTeams = {};
@@ -115,25 +151,24 @@ abstract class _ClashStore with Store {
get tournamentsToTeamsFilteredToADayIfActive {
Map> ogTeams = tournamentsToTeams;
if (filterByDay) {
- developer.log("Filtering by day");
- ogTeams = ogTeams.map((key, value) {
+ var teamy = ogTeams.map((key, value) {
return MapEntry(
key,
value.where((team) {
return isSameDay(key.startTime, filterDate);
}).toList());
});
+ return teamy;
}
- developer.log("Not filtering by day");
return ogTeams;
}
@computed
- ObservableList get events {
- List events = [];
+ ObservableList get events {
+ List events = [];
for (var entry in tournamentsToTeams.entries) {
for (var team in entry.value) {
- events.add(Event(
+ events.add(HomeEvent(
date: entry.key.startTime,
title: '${entry.key.tournamentName} ${entry.key.tournamentDay}',
description: "An event",
@@ -150,16 +185,46 @@ abstract class _ClashStore with Store {
}
@action
- Future refreshClashTournaments() async {
- tournaments = ObservableList.of(
- await _clashService.retrieveTournaments(_applicationDetailsStore.id));
+ Future refreshClashTournaments(String id) async {
+ callsInProgress.add(_ClashStore.refreshClashTournamentsCall);
+ tournaments =
+ ObservableList.of(await _clashService.retrieveTournaments(id));
+ callsInProgress.remove(_ClashStore.refreshClashTournamentsCall);
}
@action
- Future refreshClashTeams() async {
- var futureClashTeams = await _clashService.getClashTeams(
- _applicationDetailsStore.id, _applicationDetailsStore.preferredServers);
+ Future refreshClashTeams(
+ String id, List preferredServers) async {
+ callsInProgress.add(_ClashStore.refreshClashTeamsCall);
+ var futureClashTeams =
+ await _clashService.getClashTeams(id, preferredServers);
clashTeams = ObservableList.of(futureClashTeams);
+ callsInProgress.remove(_ClashStore.refreshClashTeamsCall);
+ }
+
+ @action
+ Future createTeam(String id, String name, Role role,
+ ClashTournament clashTournament, String serverId) async {
+ await _clashService.createClashTeam(
+ id,
+ name,
+ role,
+ clashTournament.tournamentName,
+ clashTournament.tournamentDay,
+ serverId);
+ refreshClashTeams(id, selectedServers);
+ }
+
+ @action
+ Future createPlayer(
+ String id, String username, String preferredServers) async {
+ await _clashService.createPlayer(id, username, preferredServers);
+ }
+
+ @action
+ Future createSelectedServers(
+ String id, List preferredServers) async {
+ await _clashService.createSelectedServers(id, preferredServers);
}
DateTime roundUpToEndOfDay(DateTime date) {
diff --git a/lib/stores/v2-stores/error_handler.store.dart b/lib/stores/v2-stores/error_handler.store.dart
new file mode 100644
index 0000000..9d5caaa
--- /dev/null
+++ b/lib/stores/v2-stores/error_handler.store.dart
@@ -0,0 +1,20 @@
+import 'package:mobx/mobx.dart';
+
+part 'error_handler.store.g.dart';
+
+class ErrorHandlerStore = _ErrorHandlerStore with _$ErrorHandlerStore;
+
+abstract class _ErrorHandlerStore with Store {
+ @observable
+ String errorMessage = '';
+
+ @action
+ void setErrorMessage(String message) {
+ errorMessage = message;
+ }
+
+ @action
+ void clearErrorMessage() {
+ errorMessage = '';
+ }
+}
diff --git a/lib/storybook_main.dart b/lib/storybook_main.dart
new file mode 100644
index 0000000..a18fdbb
--- /dev/null
+++ b/lib/storybook_main.dart
@@ -0,0 +1,340 @@
+import 'package:clash_bot_api/api.dart';
+import 'package:clashbot_flutter/globals/global_settings.dart';
+import 'package:clashbot_flutter/models/clash_team.dart';
+import 'package:clashbot_flutter/models/clash_tournament.dart';
+import 'package:clashbot_flutter/models/clashbot_user.dart';
+import 'package:clashbot_flutter/models/discord_guild.dart';
+import 'package:clashbot_flutter/models/discord_user.dart';
+import 'package:clashbot_flutter/pages/home/page/widgets/calendar_widget.dart';
+import 'package:clashbot_flutter/pages/home/page/widgets/team_card.dart';
+import 'package:clashbot_flutter/services/clashbot_service_impl.dart';
+import 'package:clashbot_flutter/services/discord_service_impl.dart';
+import 'package:clashbot_flutter/services/riot_resources_service_impl.dart';
+import 'package:clashbot_flutter/stores/application_details.store.dart';
+import 'package:clashbot_flutter/stores/discord_details.store.dart';
+import 'package:clashbot_flutter/stores/riot_champion.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/clash.store.dart';
+import 'package:clashbot_flutter/stores/v2-stores/error_handler.store.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:storybook_flutter/storybook_flutter.dart';
+
+class MockApplicationDetailsStore extends ApplicationDetailsStore {
+ MockApplicationDetailsStore(
+ ClashBotUser mockClashBotUser,
+ super._clashStore,
+ super._discordDetailsStore,
+ super._riotChampionStore,
+ super._errorHandlerStore);
+
+ @override
+ ClashBotUser get clashBotUser => ClashBotUser(
+ discordId: '123456789',
+ champions: [],
+ role: Role.TOP,
+ serverId: 'server1',
+ selectedServers: [
+ 'server1',
+ ],
+ preferredServers: ['server1', 'server2'],
+ );
+}
+
+class MockDiscordDetailsStore extends DiscordDetailsStore {
+ MockDiscordDetailsStore(List guilds, DiscordUser user,
+ super.discordService, super._errorHandlerStore);
+}
+
+class MockClashStore extends ClashStore {
+ MockClashStore(
+ ClashBotUser clashBotUser,
+ List tournaments,
+ List clashTeams,
+ super._clashService,
+ super._errorhandlerStore);
+}
+
+class MockRiotChampionStore extends RiotChampionStore {
+ MockRiotChampionStore(super._riotResourcesService, super._errorHandlerStore);
+}
+
+void main() {
+ var loggedInUserId = '123456789';
+ var clashUser = ClashBotUser(
+ discordId: loggedInUserId,
+ champions: [],
+ role: Role.TOP,
+ serverId: 'server1',
+ selectedServers: [
+ 'server1',
+ ],
+ preferredServers: ['server1', 'server2'],
+ );
+ var guilds = [
+ DiscordGuild('1', 'Mock Guild 1', '123456789', false),
+ DiscordGuild('2', 'Mock Guild 2', '123456789', false),
+ ];
+ var tournaments = [
+ ClashTournament('1', 'Mock Tournament 1', DateTime.now(), DateTime.now()),
+ ClashTournament('2', 'Mock Tournament 2', DateTime.now(), DateTime.now()),
+ ];
+ var clashTeams = [
+ ClashTeam(
+ '1',
+ 'Mock Team 1',
+ tournaments[0].tournamentName,
+ tournaments[0].tournamentDay,
+ {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.SUPP: PlayerDetails('5', 'Player 5', []),
+ },
+ '123456789',
+ DateTime.now(),
+ ),
+ ClashTeam(
+ '2',
+ 'Mock Team 2',
+ tournaments[0].tournamentName,
+ tournaments[0].tournamentDay,
+ {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.SUPP: PlayerDetails('5', 'Player 5', []),
+ },
+ '123456789',
+ DateTime.now(),
+ ),
+ ];
+ var discordUser = DiscordUser(
+ loggedInUserId, 'mock_username', '123456789', "mock_discriminator");
+ runApp(MultiProvider(providers: [
+ Provider(create: (_) => ApiClient(basePath: "http://localhost")),
+ Provider(create: (_) => ErrorHandlerStore()),
+ ProxyProvider(
+ update: (_, errorHandlerStore, __) {
+ return MockDiscordDetailsStore(guilds, discordUser,
+ DiscordServiceImpl(setupOauth2Helper()), errorHandlerStore);
+ }),
+ ProxyProvider(
+ update: (_, errorHandlerStore, __) => MockRiotChampionStore(
+ RiotResourceServiceImpl(), errorHandlerStore)),
+ ProxyProvider2(
+ update: (_, errorHandlerStore, apiClient, __) => MockClashStore(
+ clashUser,
+ tournaments,
+ clashTeams,
+ ClashBotServiceImpl(
+ UserApi(apiClient),
+ TeamApi(apiClient),
+ ChampionsApi(apiClient),
+ SubscriptionApi(apiClient),
+ TentativeApi(apiClient),
+ TournamentApi(apiClient)),
+ errorHandlerStore)),
+ ProxyProvider4(
+ update: (_, clashStore, errorHandlerStore, discordDetailsStore,
+ riotChampionStore, __) =>
+ MockApplicationDetailsStore(clashUser, clashStore,
+ discordDetailsStore, riotChampionStore, errorHandlerStore)),
+ ], child: ClashBotStorybookApp()));
+}
+
+class ClashBotStorybookApp extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return Storybook(initialStory: "4Filled", stories: [
+ StoryCalendarWidgetWTournaments(context),
+ StoryCalendarWidgetWTournamentsLoading(context),
+ StoryTeamCard()
+ ]);
+ }
+
+ Story StoryTeamCard() {
+ return Story(
+ name: "4Filled",
+ description: "A card for displaying team information",
+ builder: (context) {
+ return TeamCard(
+ team: ClashTeam(
+ '1',
+ 'Mock Team',
+ 'Tournament 1',
+ '1',
+ () {
+ switch (context.knobs
+ .text(label: '# of missing roles', initial: '0')) {
+ case '0':
+ return {
+ Role.TOP: PlayerDetails('123456789', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.BOT: PlayerDetails('5', 'Player 4', []),
+ Role.SUPP: PlayerDetails('5', 'Player 5', []),
+ };
+ case '1':
+ return {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.BOT: PlayerDetails('5', 'Player 4', []),
+ Role.SUPP: null,
+ };
+ case '2':
+ return {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.BOT: null,
+ Role.SUPP: null,
+ };
+ case '3':
+ return {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.JG: null,
+ Role.BOT: null,
+ Role.SUPP: null,
+ };
+ case '4':
+ return {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: null,
+ Role.MID: null,
+ Role.BOT: null,
+ Role.SUPP: null,
+ };
+ case '5':
+ return {
+ Role.TOP: null,
+ Role.JG: null,
+ Role.MID: null,
+ Role.BOT: null,
+ Role.SUPP: null,
+ };
+ default:
+ return {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.SUPP: PlayerDetails('5', 'Player 5', []),
+ };
+ }
+ }(),
+ '123456789',
+ DateTime.now(),
+ ));
+ });
+ }
+
+ Story StoryCalendarWidgetWTournamentsLoading(BuildContext context) {
+ DiscordDetailsStore discordDetailsStore =
+ context.read();
+ ClashStore clashStoreW5Tournies = new MockClashStore(
+ context.read().clashBotUser,
+ [
+ ClashTournament('1', 'Mock Tournament 1', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('2', 'Mock Tournament 2', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('3', 'Mock Tournament 3', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('4', 'Mock Tournament 4', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('5', 'Mock Tournament 5', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ],
+ [
+ ClashTeam(
+ '1',
+ 'Mock Team 1',
+ 'Mock Tournament 1',
+ '1',
+ {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.SUPP: PlayerDetails('5', 'Player 5', []),
+ },
+ '123456789',
+ DateTime.now(),
+ )
+ ],
+ new ClashBotServiceImpl(
+ new UserApi(context.read()),
+ new TeamApi(context.read()),
+ new ChampionsApi(context.read()),
+ new SubscriptionApi(context.read()),
+ new TentativeApi(context.read()),
+ new TournamentApi(context.read())),
+ context.read());
+ clashStoreW5Tournies.addCallInProgress('getTournaments');
+ return Story(
+ name: "Widgets/Calendar/loading",
+ description: "ClashBot's main calendar widget loading",
+ builder: (context) {
+ return CalendarWidget(
+ focusedDay: DateTime.now(),
+ selectedDay: DateTime.now(),
+ clashStore: clashStoreW5Tournies,
+ discordDetailsStore: discordDetailsStore);
+ },
+ );
+ }
+}
+
+Story StoryCalendarWidgetWTournaments(BuildContext context) {
+ DiscordDetailsStore discordDetailsStore = context.read();
+ ClashStore clashStoreW5Tournies = new MockClashStore(
+ context.read().clashBotUser,
+ [
+ ClashTournament('1', 'Mock Tournament 1', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('2', 'Mock Tournament 2', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('3', 'Mock Tournament 3', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('4', 'Mock Tournament 4', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ClashTournament('5', 'Mock Tournament 5', DateTime.now(),
+ DateTime.now().add(Duration(days: 1))),
+ ],
+ [
+ ClashTeam(
+ '1',
+ 'Mock Team 1',
+ 'Mock Tournament 1',
+ '1',
+ {
+ Role.TOP: PlayerDetails('1', 'Player 1', []),
+ Role.JG: PlayerDetails('2', 'Player 2', []),
+ Role.MID: PlayerDetails('3', 'Player 3', []),
+ Role.SUPP: PlayerDetails('5', 'Player 5', []),
+ },
+ '460520499680641035',
+ DateTime.now(),
+ )
+ ],
+ new ClashBotServiceImpl(
+ new UserApi(context.read()),
+ new TeamApi(context.read()),
+ new ChampionsApi(context.read()),
+ new SubscriptionApi(context.read()),
+ new TentativeApi(context.read()),
+ new TournamentApi(context.read())),
+ context.read());
+ return Story(
+ name: "Widgets/Calendar/filled",
+ description: "ClashBot's main calendar widget filled",
+ builder: (context) {
+ return CalendarWidget(
+ focusedDay: DateTime.now(),
+ selectedDay: DateTime.now(),
+ clashStore: clashStoreW5Tournies,
+ discordDetailsStore: discordDetailsStore);
+ },
+ );
+}
diff --git a/pubspec.lock b/pubspec.lock
index ccafc07..9f0472b 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1020,10 +1020,10 @@ packages:
dependency: "direct main"
description:
name: storybook_flutter
- sha256: "0ef97a82741e12734af3c104ef6c913af1ed808756214d23bff2bd115e547887"
+ sha256: "68f07d2caf16bd34e9cfbc479d60298a6568abfac552ea1998ef724344c6cc13"
url: "https://pub.dev"
source: hosted
- version: "0.12.0"
+ version: "0.14.1"
stream_channel:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index fac8901..b85a4e6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -49,7 +49,7 @@ dependencies:
clash_bot_api:
path: clash-bot-api
animated_text_kit: ^4.2.2
- storybook_flutter: ^0.12.0
+ storybook_flutter: ^0.14.1
validators: ^3.0.0
retry: ^3.1.1
stomp_dart_client: ^0.4.4
@@ -100,11 +100,12 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/markdown/privacy-policy.md
- - assets/images/TopIcon.webp
- - assets/images/BotIcon.webp
- - assets/images/MidIcon.webp
- - assets/images/JGIcon.webp
- - assets/images/SuppIcon.webp
+ - images/TopIcon.webp
+ - images/BotIcon.webp
+ - images/MidIcon.webp
+ - images/JGIcon.webp
+ - images/SuppIcon.webp
+ - svgs/ClashBot-HomePage.svg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
diff --git a/svgs/ClashBot-HomePage.svg b/svgs/ClashBot-HomePage.svg
new file mode 100644
index 0000000..9401f14
--- /dev/null
+++ b/svgs/ClashBot-HomePage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/test/widget/clash_notification_test.dart b/test/widget/clash_notification_test.dart
deleted file mode 100644
index 76c212b..0000000
--- a/test/widget/clash_notification_test.dart
+++ /dev/null
@@ -1,70 +0,0 @@
-import 'package:clashbot_flutter/globals/color_schemes.dart';
-import 'package:clashbot_flutter/main.dart';
-import 'package:clashbot_flutter/models/clash_notification.dart';
-import 'package:clashbot_flutter/models/discord_guild.dart';
-import 'package:clashbot_flutter/stores/application_details.store.dart';
-import 'package:clashbot_flutter/stores/discord_details.store.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:golden_toolkit/golden_toolkit.dart';
-import 'package:mockito/annotations.dart';
-import 'package:mockito/mockito.dart';
-import 'package:provider/provider.dart';
-import 'clash_notification_test.mocks.dart';
-
-@GenerateMocks([ApplicationDetailsStore, DiscordDetailsStore])
-void main() {
- testGoldens('Clash Bot Notifications - Golden', (WidgetTester tester) async {
- final mockAppStore = MockApplicationDetailsStore();
- final mockDetailsStore = MockDiscordDetailsStore();
- when(mockDetailsStore.discordGuildMap)
- .thenReturn(Map.of({"serverId": DiscordGuild("serverId", "Goon Squad", "", false)}));
- when(mockAppStore.discordDetailsStore)
- .thenReturn(mockDetailsStore);
- if (const bool.fromEnvironment("LoadFont")) {
- await loadAppFonts();
- }
- final builder = GoldenBuilder.column()
- ..addScenario(
- 'Simple',
- SizedBox(
- width: 500,
- height: 500,
- child: MaterialApp(
- themeMode: ThemeMode.dark,
- debugShowCheckedModeBanner: false,
- darkTheme: ThemeData(
- brightness: Brightness.dark,
- colorScheme: darkColorScheme,
- useMaterial3: true,
- snackBarTheme: SnackBarThemeData(
- behavior: SnackBarBehavior.floating,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10.0),
- ),
- )),
- home: const Scaffold(
- body: ClashBotNotificationsWidget(),
- ),
- ),
- ));
- await tester.pumpWidgetBuilder(Builder(
- builder: (context) {
- when(mockAppStore.sortedNotifications)
- .thenAnswer((_) => [
- ClashNotification("uuid", false, "Has created a Team New Team", "Roidrage", "serverId", DateTime.now()),
- ClashNotification("uuid", true, "message", "Some one", "serverId", DateTime.now()),
- ClashNotification("uuid", false, "message", "Shiragaku", "serverId", DateTime.now())
- ]);
- return MultiProvider(
- providers: [
- Provider(create: (_) => mockAppStore),
- ],
- child: builder.build());
- }
- ));
- await tester.tap(find.byType(Icon));
- await screenMatchesGolden(tester, 'clash_bot_notification');
- });
-}
diff --git a/test/widget/clash_notification_test.mocks.dart b/test/widget/clash_notification_test.mocks.dart
deleted file mode 100644
index 9a6769d..0000000
--- a/test/widget/clash_notification_test.mocks.dart
+++ /dev/null
@@ -1,552 +0,0 @@
-// Mocks generated by Mockito 5.4.5 from annotations
-// in clashbot_flutter/test/widget/clash_notification_test.dart.
-// Do not manually edit this file.
-
-// ignore_for_file: no_leading_underscores_for_library_prefixes
-import 'dart:async' as _i11;
-
-import 'package:clash_bot_api/api.dart' as _i10;
-import 'package:clashbot_flutter/models/clash_notification.dart' as _i9;
-import 'package:clashbot_flutter/models/clashbot_user.dart' as _i4;
-import 'package:clashbot_flutter/models/discord_guild.dart' as _i12;
-import 'package:clashbot_flutter/models/discord_user.dart' as _i6;
-import 'package:clashbot_flutter/stores/application_details.store.dart' as _i7;
-import 'package:clashbot_flutter/stores/discord_details.store.dart' as _i2;
-import 'package:clashbot_flutter/stores/riot_champion.store.dart' as _i3;
-import 'package:mobx/mobx.dart' as _i5;
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:mockito/src/dummies.dart' as _i8;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: deprecated_member_use
-// ignore_for_file: deprecated_member_use_from_same_package
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: must_be_immutable
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-// ignore_for_file: subtype_of_sealed_class
-
-class _FakeDiscordDetailsStore_0 extends _i1.SmartFake
- implements _i2.DiscordDetailsStore {
- _FakeDiscordDetailsStore_0(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-class _FakeRiotChampionStore_1 extends _i1.SmartFake
- implements _i3.RiotChampionStore {
- _FakeRiotChampionStore_1(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-class _FakeClashBotUser_2 extends _i1.SmartFake implements _i4.ClashBotUser {
- _FakeClashBotUser_2(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-class _FakeObservableList_3 extends _i1.SmartFake
- implements _i5.ObservableList {
- _FakeObservableList_3(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-class _FakeObservableMap_4 extends _i1.SmartFake
- implements _i5.ObservableMap {
- _FakeObservableMap_4(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-class _FakeReactiveContext_5 extends _i1.SmartFake
- implements _i5.ReactiveContext {
- _FakeReactiveContext_5(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-class _FakeDiscordUser_6 extends _i1.SmartFake implements _i6.DiscordUser {
- _FakeDiscordUser_6(
- Object parent,
- Invocation parentInvocation,
- ) : super(
- parent,
- parentInvocation,
- );
-}
-
-/// A class which mocks [ApplicationDetailsStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockApplicationDetailsStore extends _i1.Mock
- implements _i7.ApplicationDetailsStore {
- MockApplicationDetailsStore() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i2.DiscordDetailsStore get discordDetailsStore => (super.noSuchMethod(
- Invocation.getter(#discordDetailsStore),
- returnValue: _FakeDiscordDetailsStore_0(
- this,
- Invocation.getter(#discordDetailsStore),
- ),
- ) as _i2.DiscordDetailsStore);
-
- @override
- set discordDetailsStore(_i2.DiscordDetailsStore? _discordDetailsStore) =>
- super.noSuchMethod(
- Invocation.setter(
- #discordDetailsStore,
- _discordDetailsStore,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i3.RiotChampionStore get riotChampionStore => (super.noSuchMethod(
- Invocation.getter(#riotChampionStore),
- returnValue: _FakeRiotChampionStore_1(
- this,
- Invocation.getter(#riotChampionStore),
- ),
- ) as _i3.RiotChampionStore);
-
- @override
- set riotChampionStore(_i3.RiotChampionStore? _riotChampionStore) =>
- super.noSuchMethod(
- Invocation.setter(
- #riotChampionStore,
- _riotChampionStore,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- String get id => (super.noSuchMethod(
- Invocation.getter(#id),
- returnValue: _i8.dummyValue(
- this,
- Invocation.getter(#id),
- ),
- ) as String);
-
- @override
- set id(String? value) => super.noSuchMethod(
- Invocation.setter(
- #id,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i4.ClashBotUser get clashBotUser => (super.noSuchMethod(
- Invocation.getter(#clashBotUser),
- returnValue: _FakeClashBotUser_2(
- this,
- Invocation.getter(#clashBotUser),
- ),
- ) as _i4.ClashBotUser);
-
- @override
- set clashBotUser(_i4.ClashBotUser? value) => super.noSuchMethod(
- Invocation.setter(
- #clashBotUser,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i5.ObservableList get preferredServers => (super.noSuchMethod(
- Invocation.getter(#preferredServers),
- returnValue: _FakeObservableList_3(
- this,
- Invocation.getter(#preferredServers),
- ),
- ) as _i5.ObservableList);
-
- @override
- set preferredServers(_i5.ObservableList? value) => super.noSuchMethod(
- Invocation.setter(
- #preferredServers,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- String get error => (super.noSuchMethod(
- Invocation.getter(#error),
- returnValue: _i8.dummyValue(
- this,
- Invocation.getter(#error),
- ),
- ) as String);
-
- @override
- set error(String? value) => super.noSuchMethod(
- Invocation.setter(
- #error,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i5.ObservableList<_i9.ClashNotification> get notifications =>
- (super.noSuchMethod(
- Invocation.getter(#notifications),
- returnValue: _FakeObservableList_3<_i9.ClashNotification>(
- this,
- Invocation.getter(#notifications),
- ),
- ) as _i5.ObservableList<_i9.ClashNotification>);
-
- @override
- set notifications(_i5.ObservableList<_i9.ClashNotification>? value) =>
- super.noSuchMethod(
- Invocation.setter(
- #notifications,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i5.ObservableMap get subscription =>
- (super.noSuchMethod(
- Invocation.getter(#subscription),
- returnValue: _FakeObservableMap_4(
- this,
- Invocation.getter(#subscription),
- ),
- ) as _i5.ObservableMap);
-
- @override
- _i5.ObservableList get sortedSelectedServers => (super.noSuchMethod(
- Invocation.getter(#sortedSelectedServers),
- returnValue: _FakeObservableList_3(
- this,
- Invocation.getter(#sortedSelectedServers),
- ),
- ) as _i5.ObservableList);
-
- @override
- List<_i9.ClashNotification> get sortedNotifications => (super.noSuchMethod(
- Invocation.getter(#sortedNotifications),
- returnValue: <_i9.ClashNotification>[],
- ) as List<_i9.ClashNotification>);
-
- @override
- List<_i9.ClashNotification> get unreadNotifications => (super.noSuchMethod(
- Invocation.getter(#unreadNotifications),
- returnValue: <_i9.ClashNotification>[],
- ) as List<_i9.ClashNotification>);
-
- @override
- bool get isLoggedIn => (super.noSuchMethod(
- Invocation.getter(#isLoggedIn),
- returnValue: false,
- ) as bool);
-
- @override
- _i5.ReactiveContext get context => (super.noSuchMethod(
- Invocation.getter(#context),
- returnValue: _FakeReactiveContext_5(
- this,
- Invocation.getter(#context),
- ),
- ) as _i5.ReactiveContext);
-
- @override
- _i11.Future refreshSelectedServers() => (super.noSuchMethod(
- Invocation.method(
- #refreshSelectedServers,
- [],
- ),
- returnValue: _i11.Future.value(),
- returnValueForMissingStub: _i11.Future.value(),
- ) as _i11.Future);
-
- @override
- _i11.Future refreshClashBotUser() => (super.noSuchMethod(
- Invocation.method(
- #refreshClashBotUser,
- [],
- ),
- returnValue: _i11.Future.value(),
- returnValueForMissingStub: _i11.Future.value(),
- ) as _i11.Future);
-
- @override
- void triggerError(String? errorMessage) => super.noSuchMethod(
- Invocation.method(
- #triggerError,
- [errorMessage],
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- void notifyUser(_i9.ClashNotification? clashNotification) =>
- super.noSuchMethod(
- Invocation.method(
- #notifyUser,
- [clashNotification],
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- void readNotification(String? uuid) => super.noSuchMethod(
- Invocation.method(
- #readNotification,
- [uuid],
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- void unsubscribeFromServer(String? serverId) => super.noSuchMethod(
- Invocation.method(
- #unsubscribeFromServer,
- [serverId],
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- void subscribeToServer(String? serverId) => super.noSuchMethod(
- Invocation.method(
- #subscribeToServer,
- [serverId],
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i11.Future loadUserDetails() => (super.noSuchMethod(
- Invocation.method(
- #loadUserDetails,
- [],
- ),
- returnValue: _i11.Future.value(),
- returnValueForMissingStub: _i11.Future.value(),
- ) as _i11.Future);
-
- @override
- _i11.Future<_i4.ClashBotUser> createUser(
- String? defaultServerId,
- List? selectedServersToUse,
- ) =>
- (super.noSuchMethod(
- Invocation.method(
- #createUser,
- [
- defaultServerId,
- selectedServersToUse,
- ],
- ),
- returnValue: _i11.Future<_i4.ClashBotUser>.value(_FakeClashBotUser_2(
- this,
- Invocation.method(
- #createUser,
- [
- defaultServerId,
- selectedServersToUse,
- ],
- ),
- )),
- ) as _i11.Future<_i4.ClashBotUser>);
-}
-
-/// A class which mocks [DiscordDetailsStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockDiscordDetailsStore extends _i1.Mock
- implements _i2.DiscordDetailsStore {
- MockDiscordDetailsStore() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i6.DiscordUser get discordUser => (super.noSuchMethod(
- Invocation.getter(#discordUser),
- returnValue: _FakeDiscordUser_6(
- this,
- Invocation.getter(#discordUser),
- ),
- ) as _i6.DiscordUser);
-
- @override
- set discordUser(_i6.DiscordUser? value) => super.noSuchMethod(
- Invocation.setter(
- #discordUser,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i5.ObservableList<_i12.DiscordGuild> get discordGuilds =>
- (super.noSuchMethod(
- Invocation.getter(#discordGuilds),
- returnValue: _FakeObservableList_3<_i12.DiscordGuild>(
- this,
- Invocation.getter(#discordGuilds),
- ),
- ) as _i5.ObservableList<_i12.DiscordGuild>);
-
- @override
- set discordGuilds(_i5.ObservableList<_i12.DiscordGuild>? value) =>
- super.noSuchMethod(
- Invocation.setter(
- #discordGuilds,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- _i5.ObservableMap get discordIdToName => (super.noSuchMethod(
- Invocation.getter(#discordIdToName),
- returnValue: _FakeObservableMap_4(
- this,
- Invocation.getter(#discordIdToName),
- ),
- ) as _i5.ObservableMap);
-
- @override
- set discordIdToName(_i5.ObservableMap? value) =>
- super.noSuchMethod(
- Invocation.setter(
- #discordIdToName,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- String get status => (super.noSuchMethod(
- Invocation.getter(#status),
- returnValue: _i8.dummyValue(
- this,
- Invocation.getter(#status),
- ),
- ) as String);
-
- @override
- set status(String? value) => super.noSuchMethod(
- Invocation.setter(
- #status,
- value,
- ),
- returnValueForMissingStub: null,
- );
-
- @override
- bool get detailsLoaded => (super.noSuchMethod(
- Invocation.getter(#detailsLoaded),
- returnValue: false,
- ) as bool);
-
- @override
- bool get guildDetailsLoaded => (super.noSuchMethod(
- Invocation.getter(#guildDetailsLoaded),
- returnValue: false,
- ) as bool);
-
- @override
- Map get discordGuildMap => (super.noSuchMethod(
- Invocation.getter(#discordGuildMap),
- returnValue: {},
- ) as Map);
-
- @override
- _i5.ReactiveContext get context => (super.noSuchMethod(
- Invocation.getter(#context),
- returnValue: _FakeReactiveContext_5(
- this,
- Invocation.getter(#context),
- ),
- ) as _i5.ReactiveContext);
-
- @override
- _i11.Future<_i6.DiscordUser> fetchUserDetails(String? discordId) =>
- (super.noSuchMethod(
- Invocation.method(
- #fetchUserDetails,
- [discordId],
- ),
- returnValue: _i11.Future<_i6.DiscordUser>.value(_FakeDiscordUser_6(
- this,
- Invocation.method(
- #fetchUserDetails,
- [discordId],
- ),
- )),
- ) as _i11.Future<_i6.DiscordUser>);
-
- @override
- _i11.Future fetchCurrentUserDetails() => (super.noSuchMethod(
- Invocation.method(
- #fetchCurrentUserDetails,
- [],
- ),
- returnValue: _i11.Future.value(),
- returnValueForMissingStub: _i11.Future.value(),
- ) as _i11.Future);
-
- @override
- _i11.Future fetchUserGuilds() => (super.noSuchMethod(
- Invocation.method(
- #fetchUserGuilds,
- [],
- ),
- returnValue: _i11.Future.value(),
- returnValueForMissingStub: _i11.Future.value(),
- ) as _i11.Future);
-
- @override
- _i11.Future loadEverything() => (super.noSuchMethod(
- Invocation.method(
- #loadEverything,
- [],
- ),
- returnValue: _i11.Future.value(),
- returnValueForMissingStub: _i11.Future.value(),
- ) as _i11.Future);
-}
diff --git a/web/favicon.png b/web/favicon.png
deleted file mode 100644
index 8aaa46a..0000000
Binary files a/web/favicon.png and /dev/null differ
diff --git a/web/favicon.svg b/web/favicon.svg
new file mode 100644
index 0000000..c3ba17b
--- /dev/null
+++ b/web/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png
index b749bfe..f828f30 100644
Binary files a/web/icons/Icon-192.png and b/web/icons/Icon-192.png differ
diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png
index 88cfd48..7edf04f 100644
Binary files a/web/icons/Icon-512.png and b/web/icons/Icon-512.png differ
diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png
deleted file mode 100644
index eb9b4d7..0000000
Binary files a/web/icons/Icon-maskable-192.png and /dev/null differ
diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png
deleted file mode 100644
index d69c566..0000000
Binary files a/web/icons/Icon-maskable-512.png and /dev/null differ
diff --git a/web/index.html b/web/index.html
index 7b3698e..cad678d 100644
--- a/web/index.html
+++ b/web/index.html
@@ -26,10 +26,10 @@
-
+
-
+
Clash Bot 2.0
diff --git a/web/manifest.json b/web/manifest.json
index 51d517d..35fdb72 100644
--- a/web/manifest.json
+++ b/web/manifest.json
@@ -14,23 +14,23 @@
],
"icons": [
{
- "src": "icons/Icon-192.png",
+ "src": "icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
- "src": "icons/Icon-512.png",
+ "src": "icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
- "src": "icons/Icon-maskable-192.png",
+ "src": "icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
- "src": "icons/Icon-maskable-512.png",
+ "src": "icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"