import 'package:animated_text_kit/animated_text_kit.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:external_app_launcher/external_app_launcher.dart'; import 'package:fhub/backend/DataManager.dart'; import 'package:fhub/backend/DebugHelper.dart'; import 'package:fhub/backend/Dialogs.dart'; import 'package:fhub/gameInfo.dart'; import 'package:fhub/off_screen.dart'; import 'package:fhub/src/CustomWidgets.dart'; import 'package:fhub/wd_history.dart'; import 'package:fhub/wd_portal.dart'; import 'package:fhub/welcome.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:share_plus/share_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'backend/helpers.dart'; class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override State createState() => _HomeState(); } class _HomeState extends State with WidgetsBindingObserver { @override void initState() { // TODO: implement initState super.initState(); kickstartAnimations(); TxtCoinbaseAddress.text = DataManager.UserJson['wd_address'] ?? ""; WidgetsBinding.instance.addObserver(this); subscription = Connectivity() .onConnectivityChanged .listen((ConnectivityResult result) async { // Got a new connectivity status! try { final connectivityResult = await (Connectivity().checkConnectivity()); Debug.Log(connectivityResult); if (connectivityResult != ConnectivityResult.mobile && connectivityResult != ConnectivityResult.mobile && connectivityResult != ConnectivityResult.ethernet) { Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => OfflinePage(id: 0))); return; } } catch (e) {} }); } @override void dispose() { // TODO: implement dispose super.dispose(); WidgetsBinding.instance.removeObserver(this); subscription.cancel(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { // TODO: implement didChangeAppLifecycleState super.didChangeAppLifecycleState(state); // Debug.Log(state); if (state == AppLifecycleState.resumed) { Refresh(); } } void Refresh() async { await DataManager.GrabOnce(); setState(() {}); } void kickstartAnimations() async { await Future.delayed(const Duration(milliseconds: 500)); setState(() { op1 = 1; op2 = 1; op3 = 1; }); } int selectedPageId = 0; String TitleText = "Home"; var subscription; @override Widget build(BuildContext context) { final screenHeight = MediaQuery.of(context).size.height; final screenWidth = MediaQuery.of(context).size.width; return Scaffold( backgroundColor: Colors.black, extendBody: true, body: SafeArea( child: CustomBody( context: context, onAnimEnd: () { // kickstartAnimations(); setState(() {}); }, bottomNav: [ BottomNavBarItem( icon: Icons.people, active: selectedPageId == 4, onPressed: () { setState(() { TitleText = "Share"; selectedPageId = 4; }); }, ), BottomNavBarItem( icon: Icons.gamepad_outlined, active: selectedPageId == 3, onPressed: () { setState(() { TitleText = "Games"; selectedPageId = 3; }); }), BottomNavBarItem( icon: Icons.home, active: selectedPageId == 0, onPressed: () { setState(() { TitleText = "Home"; selectedPageId = 0; }); }, ), BottomNavBarItem( icon: Icons.wallet, active: selectedPageId == 1, onPressed: () { setState(() { TitleText = "Wallet"; selectedPageId = 1; }); }), BottomNavBarItem( icon: Icons.settings, active: selectedPageId == 2, onPressed: () { setState(() { TitleText = "Settings"; selectedPageId = 2; }); }), ], child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16), child: Column(children: [ Center( child: AnimatedSwitcher( duration: Duration(milliseconds: 300), transitionBuilder: (Widget child, Animation animation) { return FadeTransition( child: child, opacity: Tween(begin: 0, end: 1).animate(animation)); }, child: GradientText( key: ValueKey(TitleText), text: TitleText, gradient: LinearGradient(colors: [ Colors.white.withOpacity(0.6), Colors.white.withOpacity(0.5), Colors.white.withOpacity(0.2) ]), style: TextStyle(fontSize: 45, fontWeight: FontWeight.bold), ), )), Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: GetCurrentBody(), ) ]), ), ), )), ); } Widget GetCurrentBody() { switch (selectedPageId) { case 1: return wallet(); case 3: return games(); case 2: return settings(); case 4: return share(); default: return home(); } } double screenHeight = 0; double screenWidth = 0; Widget home() { screenHeight = MediaQuery.of(context).size.height; screenWidth = MediaQuery.of(context).size.width; return Column( children: [ InkWell( onTap: () { selectedPageId = 1; TitleText = "Wallet"; setState(() {}); }, child: TotalEarningsCard()), SizedBox( height: 30, ), GlassCard( child: Container( width: screenWidth * 0.9, padding: EdgeInsets.all(20), child: SingleChildScrollView( child: Column( children: [ Text("Challenges"), SizedBox( height: 20, ), (DataManager.Challenges.length > 0) ? ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: DataManager.Challenges.length, itemBuilder: (BuildContext context, int index) { dynamic gameJson = Helpers.GetGameFromCode( DataManager.Challenges[index][0]['game'] ?? 'spaceio'); return ChallengeList( gameName: gameJson['name'], coin: gameJson['coin'], challengesInfo: [ ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: DataManager.Challenges[index].length, itemBuilder: (BuildContext context, int index2) { return ChallengeProgress(DataManager .Challenges[index][index2]); }, ) ]); }, ) : Column( children: [ Text( "\nComplete Challenges in Games and\n EARN CRYPTO!\n\nLink a Game to receive Challenges!", textAlign: TextAlign.center, ), SizedBox(height: 20), GlassButton( color: Colors.lightBlueAccent, onTap: () { setState(() { selectedPageId = 3; }); }, child: Text( "Get Started!", style: TextStyle( fontWeight: FontWeight.w500, fontSize: 17), ), width: 200, height: 40) ], ) ], ), ), ), ) ], ); } Widget games() { return Column( children: [ Align(alignment: Alignment.topLeft, child: Text("Linked Games")), SizedBox( height: 10, ), (DataManager.LinkedGamesJson.length > 0) ? GridView.builder( shrinkWrap: true, itemCount: DataManager.LinkedGamesJson.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10.0, mainAxisSpacing: 10.0), itemBuilder: (BuildContext context, int index) { return GameCard( list: DataManager.LinkedGamesJson, index: index); }, ) : GlassCard( child: Padding( padding: const EdgeInsets.all(15.0), child: Text( "Install a game from the list below and Link it to FaucetHub(FH) to Start Earning!", style: TextStyle(color: Colors.blue.withGreen(150).withRed(100)), textAlign: TextAlign.center, ), )), SizedBox( height: 25, ), Align(alignment: Alignment.topLeft, child: Text("Non-Linked Games")), SizedBox( height: 10, ), GridView.builder( shrinkWrap: true, itemCount: DataManager.NonLinkedGamesJson.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10.0, mainAxisSpacing: 10.0), itemBuilder: (BuildContext context, int index) { return GameCard(list: DataManager.NonLinkedGamesJson, index: index); }, ) ], ); } Widget GameCard({required int index, required List list}) { return GlassCard( child: InkWell( onTap: () async { await Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) => GameInfoPage(gameJson: list[index]))); await DataManager.GrabOnce(); setState(() {}); }, child: Container( padding: EdgeInsets.all(12), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( list[index]['name'], style: TextStyle(fontSize: 16), ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container( width: 50, child: ClipRRect( borderRadius: BorderRadius.circular(10), child: CachedNetworkImage( imageUrl: list[index]['icon'], ) // child: Image.network(list[index]['icon']) )), Icon(Helpers.GetIconForCrypto(list[index]['coin'])) ], ), Text(list[index]['description'], style: TextStyle(fontSize: 13)), ], ), ), )); } Widget TotalEarningsCard() { return GlassCard( child: Container( // height: screenHeight * 0.18, width: screenWidth * 0.9, padding: EdgeInsets.all(20), child: Column( children: [ Text("Total Earnings"), SizedBox( height: 10, ), Text('~ \$${DataManager.currentEarnings.toStringAsFixed(2)} ', style: TextStyle(fontSize: 50)), ], ), ), ); } ScrollController scrollController = ScrollController(); bool sortByGames = true; Widget wallet() { return Column( children: [ GlassCard( child: Container( // height: screenHeight * 0.18, width: screenWidth * 0.9, padding: EdgeInsets.all(20), child: Column( children: [ Text("Earnings"), SizedBox( height: 10, ), Text('~ \$${DataManager.currentEarnings.toStringAsFixed(2)} ', style: TextStyle(fontSize: 50)), SizedBox( height: 20, ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ GlassButton( onTap: () { if (DataManager.currentEarnings <= 1) { Dialogs.showAlertDialog( context, "Not Enough To Withdraw", "You need atleast \$1 to initiate a withdraw."); return; } if (!DataManager.UserJson['wd_address'] .toString() .contains("@")) { Dialogs.showAlertDialog( context, "Invalid Withdrawal Address", "Please enter a valid email address for coinbase address. Your earnings will be sent to that address via coinbase"); return; } Navigator.of(context).push(wdRoute); }, child: Text("Withdraw"), height: 40, width: 200, color: Colors.greenAccent), GlassButton( onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) => WithdrawalHistoryPage())); }, child: Icon(Icons.history), width: 60, height: 40) ], ) ], ), ), ), (DataManager.currentEarnings <= 0) ? Container() : Column(children: [ SizedBox( height: 30, ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("Sort earnings by "), SizedBox( width: 20, ), GlassCard( child: Padding( padding: const EdgeInsets.symmetric( vertical: 8.0, horizontal: 15), child: Row( children: [ InkWell( onTap: () { setState(() { sortByGames = true; }); }, child: GlassCard( highlighted: sortByGames, child: Padding( padding: EdgeInsets.symmetric( vertical: 8, horizontal: 20), child: Text("Game"), ))), SizedBox( width: 5, ), InkWell( onTap: () { setState(() { sortByGames = false; }); }, child: GlassCard( highlighted: !sortByGames, child: Padding( padding: EdgeInsets.symmetric( vertical: 8, horizontal: 20), child: Text("Crypto"), ))), ], ), )) ], ), SizedBox( height: 10, ), GlassCard( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ sortByGames ? ListView.builder( shrinkWrap: true, controller: scrollController, itemCount: DataManager.GamesEarnings.length, itemBuilder: (BuildContext context, int index) { String gameName = DataManager.GamesEarnings.keys .elementAt(index); dynamic GameJson = Helpers.GetGameFromCode(gameName); if (GameJson == null) { Debug.LogError( ("Error getting game json from ${gameName}. returned:\n$GameJson")); return GlassCard( child: Padding( padding: EdgeInsets.all(16), child: Text( "Error", textAlign: TextAlign.center, ), )); } double amount = Helpers.SatsToCoin(DataManager .GamesEarnings.values .elementAt(index)); return WalletGameListItem(GameJson, amount); }) : ListView.builder( shrinkWrap: true, controller: scrollController, itemCount: DataManager.CryptoEarnings.length, itemBuilder: (BuildContext context, int index) { return WalletCurrencyListItem(DataManager .CryptoEarnings.keys .elementAt(index)); }, ) ], ), )) ]) ], ); } TextEditingController TxtRefId = TextEditingController(); Widget share() { return Padding( padding: EdgeInsets.all(20), child: Column( children: [ GlassCard( child: Container( padding: EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("Referral Program", style: TextStyle(fontSize: 18)), SizedBox(width: 10,), InkWell(child: Container(padding: EdgeInsets.all(5),child: Icon(Icons.help),), onTap: (){ Dialogs.showAlertDialog(context, "Referral Program", "Share your Referral ID among your friends.\nFor each submission of your Referral ID, You'll receive a Reward!"); },) ], ), SizedBox( height: 20, ), // Text("Earn 0.00000500 ETH for sharing with each friend."),//${DataManager.Settings['ref_reward']} Text("Earn"), SizedBox(height: 5,), Text("0.00000100 BTC", style: TextStyle(fontWeight: FontWeight.bold,color: Colors.greenAccent,fontSize: 16)), Text("For Sharing with each Friend"), SizedBox(height: 30,), Text("Your Referral ID"), InkWell( onTap: (){ Share.share('Join this platform with my referral ${DataManager.UserJson['id']}\nhttps://play.google.com/store/apps/details?id=com.Xperience.FaucetHub'); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(DataManager.UserJson['id'].toString(),style: TextStyle(fontSize: 50,fontWeight: FontWeight.bold),), SizedBox(width: 15,), Icon(Icons.share,size: 40) ], ), ), SizedBox( height: 20, ), GlassButton(onTap: (){ if(DataManager.UserJson["refer"] != "0"){ return; } AlertDialog alert = AlertDialog( backgroundColor: Color(0xFF1F1F1F), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)), title: Text("Enter a Referral",textAlign: TextAlign.center,), content: Column( mainAxisSize: MainAxisSize.min, children: [ Text("Enter your friends Referral ID",textAlign: TextAlign.center,), TextField(controller: refController,) ], ), actions: [ TextButton( child: Text("Submit"), onPressed: () async{ Navigator.of(context).pop(); Dialogs.waiting(); await Future.delayed(const Duration(seconds: 3)); Dialogs.hide(); }, ), TextButton( child: Text("Cancel"), onPressed: () { Navigator.of(context).pop(); }, ) ], ); showDialog(context: context, builder: (BuildContext context){return alert;}); }, child: Text((DataManager.UserJson["refer"] == "0") ? "Use Referral" : "Already Reffered to ${DataManager.UserJson["refer"]}"), width: 200,height: 40, color: Colors.greenAccent), SizedBox(height: 10,) ], ), )), SizedBox(height: 20,), InkWell( onTap: () async{ await LaunchApp.openApp( androidPackageName: 'https://play.google.com/store/apps/details?id=com.Xperience.FaucetHub', // openStore: false ); await DataManager.Review(); setState(() { }); }, child: GlassCard(child: Container(padding: EdgeInsets.all(10), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("Review on Playstore", style: TextStyle(fontSize: 18)), SizedBox(width: 10,), Container(padding: EdgeInsets.all(5),child: Icon(Icons.star)), Text("5"), ], ), (DataManager.UserJson["review"] == "0") ? Text("Get 0.00000300 BTC", style: TextStyle(color: Colors.greenAccent, fontWeight: FontWeight.bold)) : Container() ], ),)), ) ], ), ); } TextEditingController refController = TextEditingController(); Widget WalletGameListItem(dynamic GameJson, double amount) { return Padding( padding: const EdgeInsets.all(3.0), child: GlassCard( child: Container( padding: const EdgeInsets.all(10.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [SizedBox(width: 100, child: Text(GameJson['name']))], ), Text( "~\$${Helpers.CryptoToDollars(amount: amount, Crypto: GameJson['coin']).toStringAsFixed(2)}"), Row( children: [ Text("${amount.toStringAsFixed(8)}"), SizedBox( width: 5, ), Icon(Helpers.GetIconForCrypto(GameJson['coin'])) ], ), ], ), )), ); } Widget WalletCurrencyListItem(String coin) { double amount = Helpers.SatsToCoin(DataManager.CryptoEarnings[coin] ?? 0); return Padding( padding: const EdgeInsets.all(3.0), child: GlassCard( child: Container( padding: const EdgeInsets.all(10.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [SizedBox(width: 100, child: Text(coin))], ), Text( "~\$${Helpers.CryptoToDollars(amount: amount, Crypto: coin).toStringAsFixed(2)}"), Row( children: [ Text("${amount.toStringAsFixed(8)}"), SizedBox( width: 5, ), Icon(Helpers.GetIconForCrypto(coin)) ], ), ], ), )), ); } TextEditingController TxtCoinbaseAddress = TextEditingController(); Widget settings() { return Column( children: [ GlassCard( child: AnimatedSize( duration: const Duration(milliseconds: 200), child: Padding( padding: EdgeInsets.all(15), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Coinbase Address"), InkWell( onTap: () { Dialogs.ShowCoinbaseDialog(context); }, child: Icon(Icons.help)) ], ), TextField( controller: TxtCoinbaseAddress, onChanged: (e) { setState(() {}); }, ), (TxtCoinbaseAddress.text != (DataManager.UserJson['wd_address'] ?? "")) ? Container( padding: EdgeInsets.all(10), child: GlassButton( onTap: () async { String response = await DataManager.SetWdAddress( TxtCoinbaseAddress.text); bool success = response == TxtCoinbaseAddress.text; // DataManager.UserJson['wd_address'] = TxtCoinbaseAddress.text; if (!success) { Dialogs.showAlertDialog(context, "Error saving Coinbase Address", response); } setState(() {}); }, child: Text("Save"), width: 250), ) : Container() ], ), ), )), SizedBox( height: 10, ), InkWell( onTap: () async { final prefs = await SharedPreferences.getInstance(); prefs.clear(); Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute(builder: (context) => MyHomePage()), (Route route) => false); DataManager.Reset(); }, child: GlassCard( child: Padding( padding: const EdgeInsets.all(15.0), child: Row( children: [ Row( children: [ Icon(Icons.logout), SizedBox( width: 10, ), Text("Signout"), ], ) ], ), )), ) ], ); } Widget ChallengeList( {required String gameName, required String coin, required List challengesInfo}) { return Padding( padding: const EdgeInsets.all(8.0), child: GlassCard( child: Container( width: screenWidth * 0.8, padding: EdgeInsets.all(15), child: Column(children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(gameName, style: TextStyle(fontSize: 16)), Row( children: [ Icon(Helpers.GetIconForCrypto(coin)), Text(" $coin") ], ) ], ), SizedBox( height: 20, ), Column( children: challengesInfo, ) ]), )), ); } Widget ChallengeProgress(dynamic ChallengeData) { int value = int.parse(ChallengeData['current'].toString()); int max = int.parse(ChallengeData['total'].toString()); String reward = ChallengeData['reward']; bool isDone = value >= max; return Padding( padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 5), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(Icons.diamond), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(ChallengeData['name'], style: TextStyle(fontSize: 13)), isDone ? SizedBox( width: 80, child: Text( "$reward Sats", style: TextStyle(fontSize: 15, color: Colors.greenAccent), textAlign: TextAlign.end, )) : GlassProgressBar( width: screenWidth * 0.4, value: value / max) ], ), SizedBox( width: 10, ), Column( children: [ !isDone ? Column( children: [ SizedBox( width: 80, child: Text( "$reward Sats", style: TextStyle( fontSize: 15, color: Colors.greenAccent), textAlign: TextAlign.end, )), SizedBox( width: 80, child: Text( "$value/$max", style: TextStyle(fontSize: 12), textAlign: TextAlign.end, )), ], ) : Container( padding: EdgeInsets.fromLTRB(10, 5, 0, 0), child: GlassButton( onTap: () async { Debug.Log("Button"); setState(() {}); showDialog( context: context!, barrierDismissible: false, routeSettings: const RouteSettings(name: "Progress"), builder: (BuildContext context) { return AlertDialog( // backgroundColor: Colors.deepPurpleAccent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30)), title: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SpinKitDualRing( color: Colors.deepPurpleAccent), Expanded( child: Text( "Loading", textAlign: TextAlign.center, )), ], ), ); }); await DataManager.ClaimChallenge(ChallengeData); await Future.delayed(const Duration(seconds: 1)); Navigator.of(context).pop(); setState(() {}); }, child: Text("Claim"), width: 80, color: Colors.greenAccent), ), ], ) ], ), ); } }