diff --git a/lib/MVP/Models/AccountModel.dart b/lib/Accounts/AccountModel.dart similarity index 92% rename from lib/MVP/Models/AccountModel.dart rename to lib/Accounts/AccountModel.dart index e4e7991c..66a6df62 100644 --- a/lib/MVP/Models/AccountModel.dart +++ b/lib/Accounts/AccountModel.dart @@ -22,7 +22,7 @@ class AccountModel extends HiveObject { Uint8List? avatarBytes; @HiveField(5) - bool? isActive = false; + bool? isActive; AccountModel({ this.login, @@ -30,5 +30,6 @@ class AccountModel extends HiveObject { this.id, this.clientId, this.avatarBytes, + this.isActive = false, }); } diff --git a/lib/MVP/Models/AccountModel.g.dart b/lib/Accounts/AccountModel.g.dart similarity index 100% rename from lib/MVP/Models/AccountModel.g.dart rename to lib/Accounts/AccountModel.g.dart diff --git a/lib/Accounts/AccountsCubit.dart b/lib/Accounts/AccountsCubit.dart new file mode 100644 index 00000000..0bbf8821 --- /dev/null +++ b/lib/Accounts/AccountsCubit.dart @@ -0,0 +1,56 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:hive/hive.dart'; + +import 'AccountModel.dart'; + +class AccountsCubit extends Cubit> { + Box accountBox; + + static AccountModel defaultAccount = AccountModel( + id: 0, + clientId: 'kimne78kx3ncx6brgo4mv6wki5h1ko', + login: 'justinfan64537', + ); + + AccountsCubit(this.accountBox) : super([]) { + refresh(); + } + + Future refresh() async { + try { + for (var account in accountBox.values) { + if (account.token == null) { + await (account as HiveObject).delete(); + } + } + // ignore: empty_catches + } catch (e) {} + emit([ + for (var account in accountBox.values) account as AccountModel, + ]); + } + + Future add(AccountModel account) async { + await accountBox.add(account); + emit([...state, account]); + } + + Future remove(AccountModel account) async { + await account.delete(); + emit([...state]..remove(account)); + } + + Future getActive() async { + return state.firstWhere((account) => account.isActive ?? false, orElse: () => defaultAccount); + } + + Future setActive(AccountModel activeAccount) async { + for (var account in state) { + account.isActive = false; + await account.save(); + } + activeAccount.isActive = true; + await activeAccount.save(); + emit([...state]); + } +} diff --git a/lib/Badges/SevenTVBadges.dart b/lib/Badges/SevenTVBadges.dart index 1da98c1c..2bd9915b 100644 --- a/lib/Badges/SevenTVBadges.dart +++ b/lib/Badges/SevenTVBadges.dart @@ -26,7 +26,7 @@ class SevenTVBadges extends Cubit>> { description: null, id: badgeData['id'], mipmap: [ - for (var url in badgeData['urls'].take(1)) url.last, + for (var url in badgeData['urls']) url.last, ], name: badgeData['id'], tag: badgeData['id'], diff --git a/lib/Components/ChatInputBox.dart b/lib/Components/ChatInputBox.dart index 70343025..d53fd851 100644 --- a/lib/Components/ChatInputBox.dart +++ b/lib/Components/ChatInputBox.dart @@ -138,22 +138,22 @@ class _ChatInputBoxState extends State { }, ), ), - AspectRatio( - aspectRatio: 1.0, - child: Container( - height: 32.0, - child: InkWell( - onTap: () async => await UploadModal.show( - context, - channel: widget.channel!, - ), - child: Icon( - Icons.file_present, - color: Theme.of(context).colorScheme.onSurface.withAlpha(64 * 3), - ), - ), - ), - ), + // AspectRatio( + // aspectRatio: 1.0, + // child: Container( + // height: 32.0, + // child: InkWell( + // onTap: () async => await UploadModal.show( + // context, + // channel: widget.channel!, + // ), + // child: Icon( + // Icons.file_present, + // color: Theme.of(context).colorScheme.onSurface.withAlpha(64 * 3), + // ), + // ), + // ), + // ), AspectRatio( aspectRatio: 1.0, child: Container( diff --git a/lib/Components/HomeDrawer.dart b/lib/Components/HomeDrawer.dart index f0d75903..cece333b 100644 --- a/lib/Components/HomeDrawer.dart +++ b/lib/Components/HomeDrawer.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '/Components/UI/WidgetBlur.dart'; import '/Pages/Account.dart'; -import '/Pages/Profile.dart'; import '/Pages/Search.dart'; import '/Pages/Whispers.dart'; import '/StreamOverlay/StreamOverlayBloc.dart'; @@ -87,7 +86,7 @@ class HomeDrawer extends StatelessWidget { onPressed: () => Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) => AccountPage( - client: client, + client: client!, ), ), ), diff --git a/lib/MVP/Presenters/AccountPresenter.dart b/lib/MVP/Presenters/AccountPresenter.dart deleted file mode 100644 index 589001ec..00000000 --- a/lib/MVP/Presenters/AccountPresenter.dart +++ /dev/null @@ -1,50 +0,0 @@ -import '/MVP/Models/AccountModel.dart'; -import 'package:hive/hive.dart'; - -/// [AccountPresenter] is the presenter used for our accounts. It saves and loads in a list of [AccountModel] models. -class AccountPresenter { - static Future> loadData() async { - var box = await Hive.openBox('Accounts'); - var data = []; - if (box.isEmpty) { - data.add( - AccountModel( - id: 0, - clientId: 'kimne78kx3ncx6brgo4mv6wki5h1ko', - login: 'justinfan64537', - ), - ); - await saveData(data); - return await loadData(); - } - for (var i = 0; i < box.length; ++i) { - data.add(box.getAt(i)); - } - return data; - } - - static Future saveData(List models) async { - var box = await Hive.openBox('Accounts'); - await box.clear(); - await box.addAll(models); - } - - static Future findCurrentAccount() async { - var box = await Hive.openBox('SettingsOld'); - var currentId = box.containsKey('currentAccountId') ? box.get('currentAccountId') : 0; - var accounts = await loadData(); - return accounts.firstWhere((element) => element!.isActive!, orElse: () => accounts.first); - } - - static void setCurrentAccount(AccountModel? model) async { - var box = await Hive.openBox('SettingsOld'); - var currentId = box.containsKey('currentAccountId') ? box.get('currentAccountId') : 0; - var accounts = await loadData(); - for (var account in accounts) { - if (account!.isActive!) account.isActive = false; - if (account.id == model!.id) account.isActive = true; - await account.save(); - } - saveData(accounts); - } -} diff --git a/lib/MVP/Views/AccountView.dart b/lib/MVP/Views/AccountView.dart deleted file mode 100644 index 24c0b6b4..00000000 --- a/lib/MVP/Views/AccountView.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter/material.dart'; -import '/Components/UI/WidgetBlur.dart'; -import '/MVP/Presenters/AccountPresenter.dart'; -import '../../Pages/OAuth.dart'; -import 'package:flutter_chatsen_irc/Twitch.dart' as twitch; - -/// [AccountView] is our settings view that allows to change accounts. It uses the [AccountPresenter] to fetch and save a [AccountModel] model that contains our configuration. -class AccountView extends StatefulWidget { - final twitch.Client? client; - - const AccountView({ - Key? key, - required this.client, - }) : super(key: key); - - @override - _AccountViewState createState() => _AccountViewState(); -} - -class _AccountViewState extends State { - Future? accounts; - - void refresh() async { - accounts = AccountPresenter.loadData(); - setState(() {}); - } - - @override - void initState() { - refresh(); - super.initState(); - } - - @override - Widget build(BuildContext context) => FutureBuilder( - future: accounts, - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - return ListView( - children: [ - for (var account in snapshot.data) - ListTile( - title: Text(account.token != null ? account.login : 'Anonymous Login'), - subtitle: Text(account.token != null ? account.clientId : account.login), - trailing: account.token != null - ? IconButton( - icon: Icon(Icons.delete), - onPressed: () async { - snapshot.data.remove(account); - AccountPresenter.saveData(snapshot.data); - setState(() {}); - }, - ) - : null, - leading: (account.avatarBytes != null) - ? ClipRRect( - borderRadius: BorderRadius.circular(128.0), - child: Image.memory(account.avatarBytes), - ) - : Padding( - padding: const EdgeInsets.all(4.0), - child: Icon(Icons.account_circle, size: 48.0), - ), - onTap: () async { - widget.client!.swapCredentials( - twitch.Credentials( - clientId: account.clientId, - id: account.id, - login: account.login, - token: account.token, - ), - ); - AccountPresenter.setCurrentAccount(account); - Navigator.of(context).pop(); - }, - ), - // ListTile( - // leading: Padding( - // padding: const EdgeInsets.all(12.0), - // child: Icon(Icons.add, size: 32.0), - // ), - // title: Text('Add account'), - // onTap: () async => Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => OAuthPage( - // refresh: refresh, - // ), - // ), - // ), - // ), - ListTile( - leading: Padding( - padding: const EdgeInsets.all(12.0), - child: Icon(Icons.add, size: 32.0), - ), - title: Text('Add account'), - onTap: () async => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => OAuthPage( - // client: widget.client!, - refresh: refresh, - ), - ), - ), - ), - ], - ); - } - return CircularProgressIndicator.adaptive(); - }, - ); -} diff --git a/lib/Pages/Account.dart b/lib/Pages/Account.dart index e523a3b9..843b553e 100644 --- a/lib/Pages/Account.dart +++ b/lib/Pages/Account.dart @@ -1,23 +1,200 @@ +import 'dart:math'; + +import 'package:chatsen/Accounts/AccountModel.dart'; +import 'package:chatsen/Accounts/AccountsCubit.dart'; +import 'package:chatsen/Components/UI/Tile.dart'; +import 'package:chatsen/Pages/OAuth.dart'; import 'package:flutter/material.dart'; -import '/MVP/Views/AccountView.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_chatsen_irc/Twitch.dart' as twitch; -/// [AccountPage] is the Page scaffold representing our app's autocompletion settings. It allows changing the look and feel of autocompletion. -class AccountPage extends StatelessWidget { - final twitch.Client? client; +class AccountPage extends StatefulWidget { + final twitch.Client client; const AccountPage({ Key? key, required this.client, }) : super(key: key); + @override + State createState() => _AccountPageState(); +} + +class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { + final double minHeight; + final double maxHeight; + final Widget child; + + _SliverAppBarDelegate({ + required this.minHeight, + required this.maxHeight, + required this.child, + }); + + @override + double get minExtent => minHeight; + + @override + double get maxExtent => max(maxHeight, minHeight); + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => SizedBox.expand(child: child); + + @override + bool shouldRebuild(_SliverAppBarDelegate oldDelegate) => maxHeight != oldDelegate.maxHeight || minHeight != oldDelegate.minHeight || child != oldDelegate.child; +} + +class _AccountPageState extends State { + final TextEditingController searchController = TextEditingController(); + + @override + void dispose() { + searchController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: Text('Accounts'), + floatingActionButton: FloatingActionButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => OAuthPage())), + child: Icon(Icons.add), ), - body: AccountView( - client: client, + body: BlocBuilder>( + builder: (context, state) { + var listChildren = [ + for (var account in [AccountsCubit.defaultAccount, ...state].where((account) => account.login!.toLowerCase().contains(searchController.text.toLowerCase()))) + Tile( + leading: Padding( + padding: EdgeInsets.all(account.token != null ? 0.0 : 8.0), + child: account.token != null + ? ClipRRect( + borderRadius: BorderRadius.circular(128.0), + child: Image.memory( + account.avatarBytes!, + height: 32.0 + 8.0, + ), + ) + : Icon(Icons.hide_source), + ), + trailing: account != AccountsCubit.defaultAccount + ? Padding( + padding: EdgeInsets.all(0.0), + child: IconButton( + icon: Icon(Icons.delete), + onPressed: () async { + if (account.isActive == true) { + widget.client.swapCredentials( + twitch.Credentials( + clientId: AccountsCubit.defaultAccount.clientId, + id: AccountsCubit.defaultAccount.id, + login: AccountsCubit.defaultAccount.login!, + token: AccountsCubit.defaultAccount.token, + ), + ); + } + await BlocProvider.of(context).remove(account); + }, + ), + ) + : null, + title: account.token != null ? '${account.login}' : 'Anonymous User', + subtitle: account.token != null ? '${account.clientId}' : 'Login as ${account.login}', + onTap: () async { + widget.client.swapCredentials( + twitch.Credentials( + clientId: account.clientId, + id: account.id, + login: account.login!, + token: account.token, + ), + ); + if (account.token != null) await BlocProvider.of(context).setActive(account); + Navigator.of(context).pop(); + }, + ), + ]; + + return CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: SizedBox( + height: 128.0 * 1.5, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24.0) + EdgeInsets.only(top: MediaQuery.of(context).padding.top), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 24.0), + Container( + width: 24.0, + height: 24.0, + child: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () => Navigator.of(context).pop(), + padding: EdgeInsets.zero, + iconSize: 24.0, + ), + ), + Spacer(), + Text( + 'Accounts', + style: Theme.of(context).textTheme.headline4!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + ], + ), + ), + ), + ), + SliverPersistentHeader( + // pinned: true, + floating: true, + delegate: _SliverAppBarDelegate( + minHeight: 64.0 + MediaQuery.of(context).padding.top, + maxHeight: 64.0 + MediaQuery.of(context).padding.top, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0) + EdgeInsets.only(top: MediaQuery.of(context).padding.top), + child: Material( + borderRadius: BorderRadius.circular(64.0), + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Center( + child: Row( + children: [ + Icon(Icons.search), + SizedBox( + width: 12.0, + ), + Expanded( + child: TextField( + controller: searchController, + decoration: InputDecoration( + hintText: 'Search accounts', + isDense: true, + border: InputBorder.none, + ), + onChanged: (value) => setState(() {}), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) => listChildren[index], + childCount: listChildren.length, + ), + ), + ], + ); + }, ), ); } diff --git a/lib/Pages/Home.dart b/lib/Pages/Home.dart index df509874..6f286bb6 100644 --- a/lib/Pages/Home.dart +++ b/lib/Pages/Home.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:better_player/better_player.dart'; +import 'package:chatsen/Accounts/AccountsCubit.dart'; import 'package:chatsen/Components/HomeEndDrawer.dart'; import 'package:chatsen/Components/Modal/SetupModal.dart'; import 'package:chatsen/Components/Modal/UpdateModal.dart'; @@ -17,7 +18,6 @@ import '/Components/ChannelJoinModal.dart'; import '/Components/HomeDrawer.dart'; import '/Components/HomeTab.dart'; import '/Components/Notification.dart'; -import '/MVP/Presenters/AccountPresenter.dart'; import '/StreamOverlay/StreamOverlayBloc.dart'; import '/StreamOverlay/StreamOverlayState.dart'; import '/Views/Chat.dart'; @@ -54,20 +54,33 @@ class _HomePageState extends State implements twitch.Listener { @override void initState() { - AccountPresenter.findCurrentAccount().then( - (account) async { - print(account!.login); - client.swapCredentials( - twitch.Credentials( - clientId: account.clientId, - id: account.id, - login: account.login!, - token: account.token, + Future.delayed(Duration(seconds: 2)).then( + (t) => BlocProvider.of(context).getActive().then( + (account) => client.swapCredentials( + twitch.Credentials( + clientId: account.clientId, + id: account.id, + login: account.login!, + token: account.token, + ), + ), ), - ); - }, ); + // AccountPresenter.findCurrentAccount().then( + // (account) async { + // print(account!.login); + // client.swapCredentials( + // twitch.Credentials( + // clientId: account.clientId, + // id: account.id, + // login: account.login!, + // token: account.token, + // ), + // ); + // }, + // ); + loadChannelHistory(); client.listeners.add(this); diff --git a/lib/Pages/OAuth.dart b/lib/Pages/OAuth.dart index 62d1d4fe..0317c35c 100644 --- a/lib/Pages/OAuth.dart +++ b/lib/Pages/OAuth.dart @@ -1,19 +1,18 @@ import 'dart:convert'; import 'dart:io'; +import 'package:chatsen/Accounts/AccountModel.dart'; +import 'package:chatsen/Accounts/AccountsCubit.dart'; +import 'package:collection/src/iterable_extensions.dart'; import 'package:flutter/material.dart'; -import '/MVP/Presenters/AccountPresenter.dart'; -import '/MVP/Models/AccountModel.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:http/http.dart' as http; /// [OAuthPage] is the page that contains our login webview. It's used to be able to add accounts to the application. class OAuthPage extends StatefulWidget { - final Function refresh; - const OAuthPage({ Key? key, - required this.refresh, }) : super(key: key); @override @@ -35,13 +34,13 @@ class _OAuthPageState extends State { appBar: AppBar( title: Text('Login with Twitch'), actions: [ - IconButton( - icon: Icon(Icons.add), - onPressed: () async { - await webViewController.clearCache(); - await cookieManager.clearCookies(); - }, - ), + // IconButton( + // icon: Icon(Icons.add), + // onPressed: () async { + // await webViewController.clearCache(); + // await cookieManager.clearCookies(); + // }, + // ), ], ), body: WebView( @@ -65,9 +64,9 @@ class _OAuthPageState extends State { var imageBytes = (await http.get(Uri.parse(responseJson['data'][0]['profile_image_url']))).bodyBytes; - var data = await AccountPresenter.loadData(); - var existing = data.firstWhere((model) => model!.id == (int.tryParse(responseJson['data'][0]['id']) ?? -1), orElse: () => null); + var cubit = BlocProvider.of(context); + var existing = cubit.state.firstWhereOrNull((model) => model.id == (int.tryParse(responseJson['data'][0]['id']) ?? -1)); if (existing != null) { existing.clientId = 'vvxbprk8sfufgzd7k9wwr1478znf7b'; existing.token = fragmentParameters['access_token']; @@ -75,18 +74,17 @@ class _OAuthPageState extends State { existing.login = responseJson['data'][0]['login']; existing.avatarBytes = imageBytes; await existing.save(); + await cubit.setActive(existing); } else { - data.add( - AccountModel( - clientId: 'vvxbprk8sfufgzd7k9wwr1478znf7b', - token: fragmentParameters['access_token'], - id: int.tryParse(responseJson['data'][0]['id']) ?? 0, - login: responseJson['data'][0]['login'], - avatarBytes: imageBytes, - ), + var model = AccountModel( + clientId: 'vvxbprk8sfufgzd7k9wwr1478znf7b', + token: fragmentParameters['access_token'], + id: int.tryParse(responseJson['data'][0]['id']) ?? 0, + login: responseJson['data'][0]['login'], + avatarBytes: imageBytes, ); - - await AccountPresenter.saveData(data); + await cubit.add(model); + await cubit.setActive(model); } await webViewController.clearCache(); @@ -96,7 +94,6 @@ class _OAuthPageState extends State { } Navigator.of(context).pop(); - widget.refresh(); } }, initialUrl: 'https://id.twitch.tv/oauth2/authorize?client_id=vvxbprk8sfufgzd7k9wwr1478znf7b&redirect_uri=https://chatsen.app&response_type=token&scope=user_subscriptions%20user_blocks_edit%20user_blocks_read%20user_follows_edit%20channel_editor%20channel:moderate%20channel:read:redemptions%20chat:edit%20chat:read%20whispers:read%20whispers:edit%20channel_commercial%20channel:edit:commercial%20user:edit:follows%20clips:edit%20channel:manage:broadcast%20user:read:blocked_users%20user:manage:blocked_users%20moderator:manage:automod', diff --git a/lib/Pages/Profile.dart b/lib/Pages/Profile.dart deleted file mode 100644 index 149a8815..00000000 --- a/lib/Pages/Profile.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '/MVP/Models/AccountModel.dart'; -import '/MVP/Presenters/AccountPresenter.dart'; -import 'package:http/http.dart' as http; - -/// The [ProfilePage] is a page that contains the information about the current logged in user. It allows you to copy your information if you wish to or to upload a new avatar on demand. -class ProfilePage extends StatefulWidget { - @override - _ProfilePageState createState() => _ProfilePageState(); -} - -class _ProfilePageState extends State { - void changeAvatar(AccountModel? model) async { - var result = await (FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['png'], - withData: true, - ) as FutureOr); - - if (result.files.isEmpty) return; - - model!.avatarBytes = result.files.first.bytes; - model.save(); - - var uploadUrlRequest = await http.post( - Uri.parse('https://api.twitch.tv/kraken/users/${model.id}/upload_image?client_id=${model.clientId}&api_version=5&image_type=profile_image&format=png'), - headers: { - 'dnt': '1', - 'origin': 'https://www.twitch.tv', - 'referer': 'https://www.twitch.tv/', - 'Authorization': 'OAuth ${model.token}', - }, - ); - - var uploadUrlResult = jsonDecode(utf8.decode(uploadUrlRequest.bodyBytes)); - if (uploadUrlResult['upload_url'] == null) return; - - var fileRequest = http.Request( - 'PUT', - Uri.parse(uploadUrlResult['upload_url']), - )..bodyBytes = result.files.first.bytes!; - fileRequest.headers['Content-Type'] = 'image/png'; - - await fileRequest.send(); - setState(() {}); - } - - @override - Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: Text('Profile'), - ), - body: FutureBuilder( - future: AccountPresenter.findCurrentAccount(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return ListView( - children: [ - if (snapshot.data!.avatarBytes != null) - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Ink.image( - image: MemoryImage(snapshot.data!.avatarBytes!), - fit: BoxFit.fill, - width: 150, - height: 150, - child: InkWell( - onTap: () async => changeAvatar(snapshot.data), - ), - ), - ], - ), - ), - if (snapshot.data!.avatarBytes == null && snapshot.data!.token != null) - Padding( - padding: const EdgeInsets.all(16.0), - child: IconButton( - icon: Icon(Icons.upload_file), - onPressed: () async => changeAvatar(snapshot.data), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - snapshot.data!.login!, - style: Theme.of(context).textTheme.headline4, - textAlign: TextAlign.center, - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - controller: TextEditingController(text: snapshot.data!.token), - decoration: InputDecoration( - labelText: 'Token', - filled: true, - suffixIcon: IconButton( - icon: Icon(Icons.copy), - onPressed: () async => await Clipboard.setData(ClipboardData(text: snapshot.data!.token)), - ), - ), - readOnly: true, - obscureText: true, - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - controller: TextEditingController(text: snapshot.data!.clientId), - decoration: InputDecoration( - labelText: 'Client ID', - filled: true, - ), - readOnly: true, - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - controller: TextEditingController(text: snapshot.data!.id.toString()), - decoration: InputDecoration( - labelText: 'User ID', - filled: true, - ), - readOnly: true, - ), - ), - ], - ); - } - return CircularProgressIndicator.adaptive(); - }, - ), - ); -} diff --git a/lib/Pages/Settings.dart b/lib/Pages/Settings.dart index 44b62eff..7183f4bd 100644 --- a/lib/Pages/Settings.dart +++ b/lib/Pages/Settings.dart @@ -150,7 +150,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(setupScreen: !state.setupScreen))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(setupScreen: value))), value: state.setupScreen, ), @@ -164,7 +164,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(notificationOnWhisper: !state.notificationOnWhisper))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(notificationOnWhisper: value))), value: state.notificationOnWhisper, ), @@ -178,7 +178,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(notificationOnMention: !state.notificationOnMention))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(notificationOnMention: value))), value: state.notificationOnMention, ), @@ -202,7 +202,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageTimestamp: !state.messageTimestamp))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageTimestamp: value))), value: state.messageTimestamp, ), @@ -216,7 +216,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageImagePreview: !state.messageImagePreview))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageImagePreview: value))), value: state.messageImagePreview, ), @@ -230,7 +230,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageLines: !state.messageLines))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageLines: value))), value: state.messageLines, ), @@ -245,7 +245,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageAlternateBackground: !state.messageAlternateBackground))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(messageAlternateBackground: value))), value: state.messageAlternateBackground, ), @@ -267,7 +267,7 @@ class _SettingsPageState extends State { title: title, subtitle: description, onTap: () => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(historyEnabled: !state.historyUseRecentMessages))), - trailing: Switch( + trailing: Switch.adaptive( onChanged: (bool value) => BlocProvider.of(context).add(SettingsChange(state: state.copyWith(historyEnabled: value))), value: state.historyUseRecentMessages, ), diff --git a/lib/Theme/ThemeManager.dart b/lib/Theme/ThemeManager.dart index 0c3bc8e9..3e3e1889 100644 --- a/lib/Theme/ThemeManager.dart +++ b/lib/Theme/ThemeManager.dart @@ -60,7 +60,7 @@ class ThemeManager { labelColor: colorScheme.primary, unselectedLabelColor: colorScheme.onSurface.withAlpha(192), ), - platform: TargetPlatform.fuchsia, + // platform: TargetPlatform.fuchsia, visualDensity: VisualDensity.adaptivePlatformDensity, pageTransitionsTheme: const PageTransitionsTheme( builders: { diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index 75f7ed74..1f77dd58 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -5,7 +5,7 @@ // ignore_for_file: lines_longer_than_80_chars import 'package:device_info_plus_web/device_info_plus_web.dart'; -import 'package:file_picker/_internal/file_picker_web.dart'; +import 'package:file_picker/src/file_picker_web.dart'; import 'package:file_selector_web/file_selector_web.dart'; import 'package:package_info_plus_web/package_info_plus_web.dart'; import 'package:share_plus_web/share_plus_web.dart'; diff --git a/lib/main.dart b/lib/main.dart index 0b76f309..967798c4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:chatsen/Accounts/AccountsCubit.dart'; import 'package:chatsen/Badges/ChatterinoBadges.dart'; import 'package:chatsen/Badges/FFZBadges.dart'; import 'package:chatsen/Theme/ThemeBloc.dart'; @@ -12,11 +13,11 @@ import 'package:hive/hive.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:device_info_plus/device_info_plus.dart'; +import 'Accounts/AccountModel.dart'; import 'App.dart'; import 'Badges/ChatsenBadges.dart'; import 'Badges/FFZAPBadges.dart'; import 'Badges/SevenTVBadges.dart'; -import 'MVP/Models/AccountModel.dart'; import 'Mentions/MentionsCubit.dart'; import 'Settings/Settings.dart'; import 'StreamOverlay/StreamOverlayBloc.dart'; @@ -39,18 +40,19 @@ void main() async { } else { Hive.init('.'); } + Hive.registerAdapter(AccountModelAdapter()); - await Hive.openBox('Accounts'); - await Hive.openBox('SettingsOld'); var settingsBox = await Hive.openBox('Settings'); var themeBox = await Hive.openBox('Theme'); + var accountsBox = await Hive.openBox('Accounts'); // timeDilation = 4.0; runApp( MultiBlocProvider( providers: [ + BlocProvider(create: (BuildContext context) => AccountsCubit(accountsBox)), BlocProvider(create: (BuildContext context) => FFZAPBadges()), BlocProvider(create: (BuildContext context) => FFZBadges()), BlocProvider(create: (BuildContext context) => ChatterinoBadges()), diff --git a/pubspec.yaml b/pubspec.yaml index d1ef97ef..06911563 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ environment: dependencies: flutter: sdk: flutter - cupertino_icons: ^1.0.3 + chupertino_icons: ^1.0.3 url_launcher: ^6.0.6 hive: ^2.0.4 hive_flutter: ^1.0.0